Compare commits

..

63 Commits
v39.0 ... v37.1

Author SHA1 Message Date
Bo Chen
115c455eaf build: Release v37.1 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-03-14 20:39:27 -07:00
Bo Chen
259b8aa1c8 tests: Run "test_live_upgrade_numa" on aarch64 only
Our Azure VM for x86_64 workers are now much smaller, and does not have
enough RAM to run the "test_live_upgrade_numa" test. Instead, this test
will still be tested on the aarch64 worker, and the "local" upgrade
variation of the same test will also be tested on all workers. So we
should be good from test coverage point of view.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-03-14 19:52:57 -07:00
Bo Chen
2a9978f3c0 tests: Enable live upgrade tests
Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-03-14 19:52:57 -07:00
Bo Chen
3c4ff7de01 hypervisor: Use legacy definitions of kvm structs for live-upgrade
Use 'kvm_vcpu_events_old' and 'kvm_clock_data_old' to support
deserialization from legacy definitions of kvm structs, so that we can
support live-upgrade from previous point releases.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-03-14 19:52:57 -07:00
Bo Chen
de6d6f2558 hypervisor: Make (de)serialize for XsaveState backward compatible
Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-03-14 19:52:57 -07:00
Rob Bradford
baf719c6ff tests: Remove unnecessary use of vec![] macro
Beta clippy fix

warning: useless use of `vec!`
    --> tests/integration.rs:5845:23
     |
5845 |         let kernels = vec![direct_kernel_boot_path()];
     |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[direct_kernel_boot_path()]`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
     = note: `#[warn(clippy::useless_vec)]` on by default

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 61afd93a50)
2024-03-14 19:52:57 -07:00
Rob Bradford
c59c61a983 vmm: Make thread local initialiser constant
Beta clippy fix:

warning: initializer for `thread_local` value can be made `const`
  --> vmm/src/sigwinch_listener.rs:27:40
   |
27 |     static TX: RefCell<Option<File>> = RefCell::new(None);
   |                                        ^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(None) }`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#thread_local_initializer_can_be_made_const
   = note: `#[warn(clippy::thread_local_initializer_can_be_made_const)]` on by default

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 9dfc39d336)
2024-03-14 19:52:57 -07:00
Rob Bradford
448fafd23a vmm: Directly clone console resize pipe
Beta clippy fix:

warning: this call to `as_ref.map(...)` does nothing
    --> vmm/src/device_manager.rs:1234:9
     |
1234 |         self.console_resize_pipe.as_ref().map(Arc::clone)
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self.console_resize_pipe.clone()`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
     = note: `#[warn(clippy::useless_asref)]` on by default

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit e70bf59809)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
196a59f209 tests: Migrate docker container from ubuntu 20.04 to 22.04
The following tests have been temporarily disabled:

1. Live upgrade/migration test with ovs-dpdk (#5532);
2. Disk hotplug tests on windows guests (#6037);

This patch has been tested with PR #6048.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
Tested-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 24f384d239)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
35d1998965 vmm: Replace Debug with Display rendering in HTTP error message
Bumping anyhow crate from 1.0.75 to 1.0.79 will cause seccomp
failures through integration tests. Newly added backtrace support
relies on readlink and many other syscalls.

Issue noticed with test_api_http_pause_resume test, where second time
of VM PAUSE or VM RESUME prints error and causes panic.
Noticed that panic message in a thread which is not allowed to write
output triggered the issue.

So implementing Display trait for HttpError and ApiError enums to avoid
adding many syscalls to seccomp filter section.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit 895dc12a74)
2024-03-14 19:52:57 -07:00
Bo Chen
c5904a413e arch: Remove unused wrapper data structure for linux_loader
The `ByteValued` trait implementations for the data structures from the
'linux_loader' crate are no longer needed, and hence their wrappers can
be removed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 9b0b881351)
2024-03-14 19:52:57 -07:00
Bo Chen
7729024451 main: Clarify truncate behavior for event monitor file
Fix beta clippy issue:

error: file opened with `create`, but `truncate` behavior not defined
   --> src/main.rs:624:26
    |
624 |                         .create(true)
    |                          ^^^^^^^^^^^^- help: add: `.truncate(true)`
    |
    = help: if you intend to overwrite an existing file entirely, call `.truncate(true)`
    = help: if you instead know that you may want to keep some parts of the old file, call `.truncate(false)`
    = help: alternatively, use `.append(true)` to append to the file instead of overwriting it
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_open_options
    = note: `-D clippy::suspicious-open-options` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_open_options)]`

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit c1f4a7b295)
2024-03-14 19:52:57 -07:00
Bo Chen
5580dd6e6a tests: Avoid clippy warning of unhandled I/O bytes
Fixes beta clippy issue:

error: read amount is not handled
    --> tests/integration.rs:2121:15
     |
2121 |         match pty.read(&mut buf) {
     |               ^^^^^^^^^^^^^^^^^^
     |
     = help: use `Read::read_exact` instead, or handle partial reads
note: the result is consumed here, but the amount of I/O bytes remains unhandled
    --> tests/integration.rs:2122:13
     |
2122 | /             Ok(_) => {
2123 | |                 let output = std::str::from_utf8(&buf).unwrap().to_string();
2124 | |                 match tx.send(output) {
2125 | |                     Ok(_) => (),
2126 | |                     Err(_) => break,
2127 | |                 }
2128 | |             }
     | |_____________^
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
     = note: `#[deny(clippy::unused_io_amount)]` on by default

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 36890373cd)
2024-03-14 19:52:57 -07:00
Rob Bradford
21ea5afa0a vhost_user_block: Allow dead_code for embedded error
The embedded error in the enum will be read on debug output of the
error.

Fixes beta clippy issue:

warning: field `0` is never read
  --> vhost_user_block/src/lib.rs:64:23
   |
64 |     CreateKillEventFd(io::Error),
   |     ----------------- ^^^^^^^^^
   |     |
   |     field in this variant
   |
   = note: `#[warn(dead_code)]` on by default
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
   |
64 |     CreateKillEventFd(()),
   |                       ~~

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 107f4bdc12)
2024-03-14 19:52:57 -07:00
Rob Bradford
a09d536dc1 performance-metrics: Allow dead_code for embedded error
The embedded error in the enum will be read on debug output of the
error.

Fixes beta clippy issue:

warning: field `0` is never read
  --> performance-metrics/src/performance_tests.rs:25:11
   |
25 |     Infra(InfraError),
   |     ----- ^^^^^^^^^^
   |     |
   |     field in this variant
   |
   = note: `#[warn(dead_code)]` on by default
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
   |
25 |     Infra(()),
   |           ~~

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 8899ebd63c)
2024-03-14 19:52:57 -07:00
Rob Bradford
f8a5c149eb block: qcow: Fix beta clippy issue
warning: field `0` is never read
   --> block/src/qcow/vec_cache.rs:139:21
    |
139 |     struct NumCache(pub u64);
    |            -------- ^^^^^^^
    |            |
    |            field in this struct
    |
    = note: `#[warn(dead_code)]` on by default
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
    |
139 |     struct NumCache(());
    |                     ~~

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit c19c73cb99)
2024-03-14 19:52:57 -07:00
Yi Wang
8e6bdcbf11 build: fix clippy ptr arg issue
CI reports errors:

error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
    --> arch/src/x86_64/mod.rs:1351:19
     |
1351 |     epc_sections: &Vec<SgxEpcSection>,
     |                   ^^^^^^^^^^^^^^^^^^^ help: change this to: `&[SgxEpcSection]`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
     = note: `-D clippy::ptr-arg` implied by `-D warnings`
     = help: to override `-D warnings` add `#[allow(clippy::ptr_arg)]`

Signed-off-by: Yi Wang <foxywang@tencent.com>
(cherry picked from commit 3d6594a594)
2024-03-14 19:52:57 -07:00
Yi Wang
93631b5e23 build: fix clippy Path::join issue
CI reports clippy errors:

error: argument to `Path::join` starts with a path separator
    --> tests/integration.rs:4076:58
     |
4076 |         let serial_socket = guest.tmp_dir.as_path().join("/tmp/serial.socket");
     |                                                          ^^^^^^^^^^^^^^^^^^^^
     |
     = note: joining a path starting with separator will replace the path instead
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#join_absolute_paths

Signed-off-by: Yi Wang <foxywang@tencent.com>
(cherry picked from commit ee2f0c3cb4)
2024-03-14 19:52:57 -07:00
Yi Wang
ade953e582 build: fix clippy complex closures issue
CI reports clippy errors:

error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
   --> test_infra/src/lib.rs:93:51
    |
93  |           match (|| -> Result<(), WaitForBootError> {
    |  ___________________________________________________^
94  | |             let listener =
95  | |                 TcpListener::bind(listen_addr.as_str()).map_err(WaitForBootError::Listen)?;
96  | |             listener
...   |
145 | |             }
146 | |         })() {
    | |_________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_conditions
    = note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]`

Signed-off-by: Yi Wang <foxywang@tencent.com>
(cherry picked from commit 9c2d650cb8)
2024-03-14 19:52:57 -07:00
Rob Bradford
a3bd7eb9a0 hypervisor: kvm: Import TDX vmcall structure
Consistent with the other data structures and constants used in TDX
support code import the necessary structures from the kernel for
accessing the vmcall structure.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 3993663e5c)
2024-03-14 19:52:57 -07:00
Thomas Barrett
b0dd4e72c5 pci: vfio: naturally align bar
According to PCIe specification, a 64-bit MMIO BAR should be
naturally aligned. In addition to being more compliant with
the specification, natural aligned BARs are mapped with
the largest possible page size by the host iommu driver, which
should speed up boot time and reduce IOTLB thrashing for virtual
machines with VFIO devices.

Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
(cherry picked from commit c9f94be7ab)
2024-03-14 19:52:57 -07:00
Alyssa Ross
ed1b415bad virtio-devices: fix reading vsock connect command
The socket is nonblocking, so it's not guaranteed that it will be
possible to read the whole connect command in a single iteration of
the event loop.  To reproduce:

	(echo -n 'CONNECT '; sleep 1; echo 1234; cat) | socat STDIO UNIX-CONNECT:vsock.sock

This would produce the error:

	cloud-hypervisor: 5.509209s: <_vsock4> INFO:virtio-devices/src/vsock/unix/muxer.rs:446 -- vsock: error adding local-init connection: UnixRead(Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" })

To fix this, if we only get a partial command, we need to save it for
future iterations of the event loop, and only proceed once we've read
a complete command.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
(cherry picked from commit 48de800756)
2024-03-14 19:52:57 -07:00
Alyssa Ross
71708c9794 vmm: limit VSOCK CIDs to 32 bits
The VIRTIO specification[1] says:

> The upper 32 bits of the CID are reserved and zeroed.

We should therefore not allow the user to supply a VSOCK CID with
those bits set.  To accomplish this, limit the public API of the
virtio-vsock device to only accept 32-bit CIDs, while still using
64-bit CIDs internally since that's how virtio-vsock works.

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

Signed-off-by: Alyssa Ross <hi@alyssa.is>
(cherry picked from commit 451d3fb2f0)
2024-03-14 19:52:57 -07:00
Alyssa Ross
f58f9cf16a vmm: forbid using special VSOCK CIDs for guests
I accidentally ran a VM with CID 2 (VMADDR_CID_HOST), and very strange
and difficult to debug behavior ensued.  I don't think a virtio-vsock
device should be allowed to have any of the special CIDs
(VMADDR_CID_ANY, VMADDR_CID_HYPERVISOR, VMADDR_CID_LOCAL, VMADDR_CID_HOST).

Signed-off-by: Alyssa Ross <hi@alyssa.is>
(cherry picked from commit 7d0b85d727)
2024-03-14 19:52:57 -07:00
Thomas Barrett
a7d967215f arch: x86_64: handle npot CPU topology
This PR addresses a bug in which the cpu topology of a guest
with non power-of-two number of cores is incorrect. For example,
in some contexts, a virtual machine with 2-sockets and 12-cores
will incorrectly believe that 16 cores are on socket 1 and 8
cores are on socket 2. In other cases, common topology enumeration
software such as hwloc will crash.

The root of the problem was the way that cloud-hypervisor generates
apic_id. On x86_64, the (x2) apic_id embeds information about cpu
topology. The cpuid instruction is primarily used to discover the
number of sockets, dies, cores, threads, etc. Using this information,
the (x2) apic_id is masked to determine which {core, die, socket} the
cpu is on. When the cpu topology is not a power of two
(e.g. a 12-core machine), this requires non-contiguous (x2) apic_id.

Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
(cherry picked from commit 5c0b66529a)
2024-03-14 19:52:57 -07:00
Bo Chen
0e29fe1517 build: Bump rustix from 0.38.8 to 0.38.25
Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 026d8908fd)
2024-03-14 19:52:57 -07:00
Bo Chen
fbb648166a fuzz: Fix cargo fuzz build issue with crc32c
Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 08120b79fc)
2024-03-14 19:52:57 -07:00
Rob Bradford
ea87988f93 block: Replace use of crc32c crate with crc-any
According to crates.io the crc-any crate is actively maintained which
avoids issues with the crc32c crate and the nightly compiler.

Fixes: #6168

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit d516374c39)
2024-03-14 19:52:57 -07:00
Bo Chen
f35d573431 build: Bump vmm-sys-util crate and its consumers
This patch bumps the following crates, including `kvm-bindings@0.7.0`*,
`kvm-ioctls@0.16.0`**, `linux-loader@0.11.0`, `versionize@0.2.0`,
`versionize_derive@0.1.6`***, `vhost@0.10.0`,
`vhost-user-backend@0.13.1`, `virtio-queue@0.11.0`, `vm-memory@0.14.0`,
`vmm-sys-util@0.12.1`, and the latest of `vfio-bindings`, `vfio-ioctls`,
`mshv-bindings`,`mshv-ioctls`, and `vfio-user`.

* A fork of the `kvm-bindings` crate is being used to support
serialization of various structs for migration [1]. Also, code changes
are made to accommodate the updated `struct xsave` from the Linux
kernel. Note: these changes related to `struct xsave` break
live-upgrade.

** The new `kvm-ioctls` crate introduced breaking changes for
the `get/set_one_reg` API on `aarch64` [2], so code changes are made to
the new APIs.

*** A fork of the `versionize_derive` crate is being used to support
versionize on packed structs [3].

[1] https://github.com/cloud-hypervisor/kvm-bindings/tree/ch-v0.7.0
[2] https://github.com/rust-vmm/kvm-ioctls/pull/223
[3] https://github.com/cloud-hypervisor/versionize_derive/tree/ch-0.1.6

Fixes: #6072

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 3ce0fef7fd)
2024-03-14 19:52:57 -07:00
Thomas Barrett
a489a11ccf arch: x86_64: enable HTT flag
When the HTT flag CPUID.1.EDX[HTT] is 0, it indicates that there is
only a single logical processor in the package. When HTT is 1, it
indicates that CPUID.1.EBX[23:16] contains the number of logical
processors in the package.

When this information is not included in CPUID leaf 0x1, some cpu
topology enumeration software such as hwloc are known to crash.

Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
(cherry picked from commit 5ec47d4883)
2024-03-14 19:52:57 -07:00
Thomas Barrett
4f1fb3632b arch: x86_64: enable nested virtualization on amd if supported
When using amd topology, the svm feature flag on cpuid leaf
0x8000_0001.ecx is overwritten. We update the amd cpu topology
logic to use the flag values that originated in
KVM_GET_SUPPORTED_CPUID ioctl and override as necessary.

Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
(cherry picked from commit 7bc764d4e0)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
693e456793 build: Update ARM64 GitHub action for windows integration tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit fbcf5fb37d)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
8c1b112a60 build: Add GitHub action for metrics tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit d245e62427)
2024-03-14 19:52:57 -07:00
Rob Bradford
26cab16830 build: Avoid cancellation of release build workflow on MQ
When running on the merge group this workflow is run twice - once for
the create event (merge queue creates a new branch) and once for the
merge_group event. Unfortunately the second event would cause the first
to be cancelled - unfortunately sometimes that second event is the
create event where the job in the workflow only runs if it is also a
tag.

By creating distinct concurrency groups for each event type then the
cross cancellation can be avoided.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 6f49d7f192)
2024-03-14 19:52:57 -07:00
Rob Bradford
c588138187 build: Use authentication token to avoid GitHub rate limit
The workers share a common public IP address and often GitHub will
reject attempts to access the API due to exceeding the anonymous rate
limit threshold.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 0f71956d6d)
2024-03-14 19:52:57 -07:00
Bo Chen
4b72e5a886 build: Allow 'cancel-in-progress' for bare-metal workers
Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 46c9b9693c)
2024-03-14 19:52:57 -07:00
Rob Bradford
51febbb7fe build: Add SGX, VFIO and rate limit testing to MQ
Run these workflows as part of the merge queue to help improve testing
coverage.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit cdafe5344d)
2024-03-14 19:52:57 -07:00
Bo Chen
551d36e502 build: Add a step to fix workspace permissions on bare-metal workers
When a bare-metal worker is canceled, its workspace can be left with
files owned by the root user as a result of running tests from our
container. This patch add a step to fix workspace permissions for such
case before checking out code.

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit f48942ce3f)
2024-03-14 19:52:57 -07:00
Bo Chen
6a5a2ac83d tests: Fix test_snapshot_restore_hotplug_virtiomem on 16 cores VM
It takes longer time to restore a VM on a VM with 16 cores comparing
with ones with 64 cores.

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 0718067851)
2024-03-14 19:52:57 -07:00
Bo Chen
37666f842d build: Run integration tests on smaller VMs
Signed-off-by: Bo Chen <chen.bo@intel.com>
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 7d60ab70e6)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
a09d828713 scripts: Update Azure storage location to access images
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit 05ec6190da)
2024-03-14 19:52:57 -07:00
Rob Bradford
67904a90fc build: Cancel in progress actions on update
If the PR updated cancel outstanding jobs to conserve resources.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 1db30405e1)
2024-03-14 19:52:57 -07:00
Rob Bradford
196e653a50 build: Only run bisectability check on PRs
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 3e35529842)
2024-03-14 19:52:57 -07:00
Rob Bradford
355148c3d6 build: Only check DCO on PRs
The DCO tool doesn't understand merge_groups but we still need to have a
valid status check to allow the merge group to proceed.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 96cc1ba76c)
2024-03-14 19:52:57 -07:00
Rob Bradford
1dff2503a6 build: Skip release check on pull requests
This takes a long time and duplicates existing checks on the pull
requests.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 022f375ef8)
2024-03-14 19:52:57 -07:00
Rob Bradford
f4c85aef89 build: Only run Intel + glibc on PR builds for x86-64 tests
Run all the tests on the merge queue.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 81b95023c4)
2024-03-14 19:52:57 -07:00
Rob Bradford
0131a408bf build: Make the Windows Guest Test always pass on PR builds
When running with the merge queue the tests will be fully executed.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit f15ca1aec3)
2024-03-14 19:52:57 -07:00
Rob Bradford
bd506500d7 build: Remove unnecessary if event checks from vfio/sgx workflows
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit cb8a728dfb)
2024-03-14 19:52:57 -07:00
Rob Bradford
80724b1662 build: Use a nicer name for DCO check step
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 80aa91f24c)
2024-03-14 19:52:57 -07:00
Rob Bradford
1f6b43db49 build: Ensure all required checks run on merge_group
And clean up some of the whitespace formatting so that the "name" and
"on" are grouped away from the "jobs".

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit d9f48505fe)
2024-03-14 19:52:57 -07:00
Bo Chen
878c2275a2 ci: Remove Jenkinsfile
Most of our CI workers are now running form GitHub actions, so we are
ready to disable Jenkins CI workers.

See: #6231

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 1d098949b9)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
5fc018abdd build: Add GitHub action for Windows guest integration tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit ba6bfee4ff)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
690e10eef4 build: Add GitHub action for Rate Limiter integration tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit 57fb97e41f)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
ea12024793 build: Add GitHub action for VFIO integration tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit b765acd608)
2024-03-14 19:52:57 -07:00
Ravi kumar Veeramally
e082ed23ed build: Add GitHub action for SGX integration tests
Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
(cherry picked from commit 4fb86e9915)
2024-03-14 19:52:57 -07:00
Rob Bradford
d1953633e2 build: Add some timeouts to integration test workflow
Add top-level timeout for the jobs and also more agressive per step
timeouts.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 1fe2771a0d)
2024-03-14 19:52:57 -07:00
Rob Bradford
23f1490667 build: Add libc to matrix for x86-64 tests
To reduce issues caused by flaky tests split the musl and glibc jobs
into separate jobs. This means fewer jobs will need to be restarted for
flaky tests. This will also increase CI throughput since the musl builds
account for ~40% of the total CI time when run together with glibc.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 2e4079becb)
2024-03-14 19:52:57 -07:00
Rob Bradford
b312a970ef build: Disable "fail fast" on x86-64 GitHub action
This will help handle flakiness in the builds by requiring the minimum
number of restarts.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit d32de07be7)
2024-03-14 19:52:57 -07:00
Rob Bradford
6e544d0a30 build: Switch GitHub action ARM64 builds to musl
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 6ec83c7d8e)
2024-03-14 19:52:57 -07:00
Rob Bradford
bc84ac4699 build: Extend x86-64 GitHub action to AMD runner
Use the matrix to add a build runnind on the AMD variant of the garm
runner.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 84a6da5e93)
2024-03-14 19:52:57 -07:00
Rob Bradford
78f0f30751 tests: Remove download of unused bionic image for aarch64
The bionic image was being downloaded and converted but no test uses
this image any longer.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 6930370a03)
2024-03-14 19:52:57 -07:00
Rob Bradford
8b0d43e2fe build: Add GitHub action for ARM64 integration tests
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 89f2a4882e)
2024-03-14 19:52:57 -07:00
Rob Bradford
61430fb345 build: Add GitHub action for unit/integration testing
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
(cherry picked from commit 307a0166c5)
2024-03-14 19:52:57 -07:00
187 changed files with 4240 additions and 8130 deletions

View File

@@ -11,6 +11,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/audit@v1 - uses: actions-rs/audit-check@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,7 +15,7 @@ jobs:
- stable - stable
- beta - beta
- nightly - nightly
- "1.74.1" - "1.70"
target: target:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
@@ -29,10 +29,11 @@ jobs:
run: sudo apt install -y musl-tools run: sudo apt install -y musl-tools
- name: Install Rust toolchain (${{ matrix.rust }}) - name: Install Rust toolchain (${{ matrix.rust }})
uses: dtolnay/rust-toolchain@stable uses: actions-rs/toolchain@v1
with: with:
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }} target: ${{ matrix.target }}
override: true
- name: Build (default features) - name: Build (default features)
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks

View File

@@ -41,7 +41,7 @@ jobs:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# generate Docker tags based on the following events/attributes # generate Docker tags based on the following events/attributes
tags: | tags: |
type=raw,value=20240407-0 type=raw,value={{date 'YYYYMMDD'}}-0
type=sha type=sha
- name: Build and push - name: Build and push

View File

@@ -14,19 +14,18 @@ jobs:
- nightly - nightly
target: target:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
env:
RUSTFLAGS: -D warnings
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rust toolchain (${{ matrix.rust }}) - name: Install Rust toolchain (${{ matrix.rust }})
uses: dtolnay/rust-toolchain@stable uses: actions-rs/toolchain@v1
with: with:
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }} target: ${{ matrix.target }}
override: true
- name: Install Cargo fuzz - name: Install Cargo fuzz
run: cargo install cargo-fuzz # Temporary fix for cargo-fuzz on latest nightly: https://github.com/rust-fuzz/cargo-fuzz/issues/276
- name: Fuzz Build #run: cargo install cargo-fuzz
run: cargo install --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
- name: Cargo Fuzz Build
run: cargo fuzz build run: cargo fuzz build
- name: Fuzz Check
run: cargo fuzz check

View File

@@ -3,67 +3,135 @@ on: [create, merge_group]
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true cancel-in-progress: true
env:
GITHUB_TOKEN: ${{ github.token }}
jobs: jobs:
release: release:
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'merge_group' if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'merge_group'
name: Release ${{ matrix.platform.target }} name: Release
strategy:
fail-fast: false
matrix:
platform:
- target: x86_64-unknown-linux-gnu
args: --all --release --features mshv
name_ch: cloud-hypervisor
name_ch_remote: ch-remote
- target: x86_64-unknown-linux-musl
args: --all --release --features mshv
name_ch: cloud-hypervisor-static
name_ch_remote: ch-remote-static
- target: aarch64-unknown-linux-musl
args: --all --release
name_ch: cloud-hypervisor-static-aarch64
name_ch_remote: ch-remote-static-aarch64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install musl-gcc - name: Install musl-gcc
if: contains(matrix.platform.target, 'musl')
run: sudo apt install -y musl-tools run: sudo apt install -y musl-tools
- name: Create release directory - name: Create release directory
if: |
github.event_name == 'create' && github.event.ref_type == 'tag' &&
matrix.platform.target == 'x86_64-unknown-linux-gnu'
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }} run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
- name: Build ${{ matrix.platform.target }} - name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: houseabsolute/actions-rust-cross@v0 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.70"
target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.70"
target: x86_64-unknown-linux-musl
- name: Build
uses: actions-rs/cargo@v1
with:
toolchain: "1.70"
command: build command: build
target: ${{ matrix.platform.target }} args: --all --release --features mshv --target=x86_64-unknown-linux-gnu
args: ${{ matrix.platform.args }} - name: Static Build
strip: true uses: actions-rs/cargo@v1
toolchain: 1.74.1
- name: Copy Release Binaries
if: github.event_name == 'create' && github.event.ref_type == 'tag'
shell: bash
run: |
cp target/${{ matrix.platform.target }}/release/cloud-hypervisor ./${{ matrix.platform.name_ch }}
cp target/${{ matrix.platform.target }}/release/ch-remote ./${{ matrix.platform.name_ch_remote }}
- name: Upload Release Artifacts
if: github.event_name == 'create' && github.event.ref_type == 'tag'
uses: actions/upload-artifact@v3
with: with:
name: Artifacts for ${{ matrix.platform.target }} toolchain: "1.70"
path: | command: build
./${{ matrix.platform.name_ch }} args: --all --release --features mshv --target=x86_64-unknown-linux-musl
./${{ matrix.platform.name_ch_remote }} - name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.70"
target: aarch64-unknown-linux-musl
override: true
- name: Create Release
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
prerelease: true
- name: Upload cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/x86_64-unknown-linux-gnu/release/cloud-hypervisor
asset_name: cloud-hypervisor
asset_content_type: application/octet-stream
- name: Upload static cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/x86_64-unknown-linux-musl/release/cloud-hypervisor
asset_name: cloud-hypervisor-static
asset_content_type: application/octet-stream
- name: Upload ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-ch-remote
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
asset_name: ch-remote
asset_content_type: application/octet-stream
- name: Upload static-ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-ch-remote
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
asset_name: ch-remote-static
asset_content_type: application/octet-stream
- name: Clean build tree ahead of cross build
uses: actions-rs/cargo@v1
with:
command: clean
- name: Static Build (AArch64)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --all --release --target=aarch64-unknown-linux-musl
- name: Upload static AArch64 cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-aarch64-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/aarch64-unknown-linux-musl/release/cloud-hypervisor
asset_name: cloud-hypervisor-static-aarch64
asset_content_type: application/octet-stream
- name: Upload static AArch64 ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-aarch64-ch-remote
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
asset_name: ch-remote-static-aarch64
asset_content_type: application/octet-stream
- name: Vendor - name: Vendor
if: |
github.event_name == 'create' && github.event.ref_type == 'tag' &&
matrix.platform.target == 'x86_64-unknown-linux-gnu'
working-directory: ../cloud-hypervisor-${{ github.event.ref }} working-directory: ../cloud-hypervisor-${{ github.event.ref }}
run: | run: |
mkdir ../vendor-cargo-home mkdir ../vendor-cargo-home
@@ -71,24 +139,16 @@ jobs:
mkdir .cargo mkdir .cargo
cargo vendor > .cargo/config.toml cargo vendor > .cargo/config.toml
- name: Create vendored source archive - name: Create vendored source archive
if: | working-directory: ../
github.event_name == 'create' && github.event.ref_type == 'tag' && run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
matrix.platform.target == 'x86_64-unknown-linux-gnu'
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz ../cloud-hypervisor-${{ github.event.ref }}
- name: Upload cloud-hypervisor vendored source archive - name: Upload cloud-hypervisor vendored source archive
if: |
github.event_name == 'create' && github.event.ref_type == 'tag' &&
matrix.platform.target == 'x86_64-unknown-linux-gnu'
id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-artifact@v3
with:
path: cloud-hypervisor-${{ github.event.ref }}.tar.xz
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
- name: Create GitHub Release
if: github.event_name == 'create' && github.event.ref_type == 'tag' if: github.event_name == 'create' && github.event.ref_type == 'tag'
uses: softprops/action-gh-release@v1 id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
files: | upload_url: ${{ steps.create_release.outputs.upload_url }}
./${{ matrix.platform.name_ch }} asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
./${{ matrix.platform.name_ch_remote }} asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
./cloud-hypervisor-${{ github.event.ref }}.tar.xz asset_content_type: application/x-xz

View File

@@ -1,12 +0,0 @@
name: REUSE Compliance Check
on: [push, pull_request]
jobs:
reuse:
name: REUSE Compliance Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v3

View File

@@ -1,20 +0,0 @@
name: Shell scripts check
on:
pull_request:
merge_group:
push:
branches:
- main
jobs:
sh-checker:
name: Check shell scripts
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run the shell script checkers
uses: luizm/action-sh-checker@master
env:
SHFMT_OPTS: -i 4 -d
SHELLCHECK_OPTS: -x --source-path scripts

1
.gitignore vendored
View File

@@ -6,4 +6,3 @@
**/rusty-tags.vi **/rusty-tags.vi
/rpm/SOURCES /rpm/SOURCES
/.vscode /.vscode
/vendor

View File

@@ -1,12 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: cloud-hypervisor
Upstream-Contact: <>
Source: https://www.cloudhypervisor.org
Files: docs/*.md *.md
Copyright: 2024
License: CC-BY-4.0
Files: scripts/* test_data/* *.toml .git* fuzz/Cargo.lock fuzz/.gitignore resources/linux-config-* vmm/src/api/openapi/cloud-hypervisor.yaml CODEOWNERS Cargo.lock
Copyright: 2024
License: Apache-2.0

1051
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "39.0.0" version = "37.1.0"
authors = ["The Cloud Hypervisor Authors"] authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
default-run = "cloud-hypervisor" default-run = "cloud-hypervisor"
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# a.) A dependency requires it, # a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old, # b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update. # c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.74.1" rust-version = "1.70"
[profile.release] [profile.release]
lto = true lto = true
@@ -29,32 +29,37 @@ strip = false
debug = true debug = true
[dependencies] [dependencies]
anyhow = "1.0.81" anyhow = "1.0.75"
api_client = { path = "api_client" } api_client = { path = "api_client" }
clap = { version = "4.5.4", features = ["string"] } clap = { version = "4.4.7", features = ["string"] }
dhat = { version = "0.3.3", optional = true } dhat = { version = "0.3.2", optional = true }
epoll = "4.3.3" epoll = "4.3.3"
event_monitor = { path = "event_monitor" } event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" } hypervisor = { path = "hypervisor" }
libc = "0.2.153" libc = "0.2.147"
log = { version = "0.4.21", features = ["std"] } log = { version = "0.4.20", features = ["std"] }
option_parser = { path = "option_parser" } option_parser = { path = "option_parser" }
seccompiler = "0.4.0" seccompiler = "0.4.0"
serde_json = "1.0.115" serde_json = "1.0.107"
signal-hook = "0.3.17" signal-hook = "0.3.17"
thiserror = "1.0.58" thiserror = "1.0.40"
tpm = { path = "tpm"} tpm = { path = "tpm"}
tracer = { path = "tracer" } tracer = { path = "tracer" }
vmm = { path = "vmm" } vmm = { path = "vmm" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"
vm-memory = "0.14.1" vm-memory = "0.14.0"
zbus = { version = "3.15.2", optional = true } zbus = { version = "3.11.1", optional = true }
# List of patched crates
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" }
[dev-dependencies] [dev-dependencies]
dirs = "5.0.1" dirs = "5.0.0"
net_util = { path = "net_util" } net_util = { path = "net_util" }
once_cell = "1.19.0" once_cell = "1.18.0"
serde_json = "1.0.115" serde_json = "1.0.107"
test_infra = { path = "test_infra" } test_infra = { path = "test_infra" }
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -108,7 +108,7 @@ do not wish to use the pre-built binaries.
## Booting Linux ## Booting Linux
Cloud Hypervisor supports direct kernel boot (the x86-64 kernel requires the kernel Cloud Hypervisor supports direct kernel boot (the x86-64 kernel requires the kernel
built with PVH support or a bzImage) or booting via a firmware (either [Rust Hypervisor built with PVH support) or booting via a firmware (either [Rust Hypervisor
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.) edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
@@ -175,7 +175,7 @@ $ ./cloud-hypervisor \
#### Building your Kernel #### Building your Kernel
Cloud Hypervisor also supports direct kernel boot. For x86-64, a `vmlinux` ELF kernel (compiled with PVH support) or a regular bzImage are supported. In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice. Cloud Hypervisor also supports direct kernel boot. For x86-64, a `vmlinux` ELF kernel (compiled with PVH support) is needed. In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
To build the kernel: To build the kernel:

View File

@@ -10,19 +10,21 @@ sev_snp = []
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.81" anyhow = "1.0.75"
byteorder = "1.5.0" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.153" libc = "0.2.147"
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] } linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
log = "0.4.21" log = "0.4.20"
serde = { version = "1.0.197", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
thiserror = "1.0.58" thiserror = "1.0.40"
uuid = "1.8.0" uuid = "1.3.4"
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-bitmap"] } versionize = "0.2.0"
versionize_derive = "0.1.6"
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] } vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
[target.'cfg(target_arch = "aarch64")'.dependencies] [target.'cfg(target_arch = "aarch64")'.dependencies]
fdt_parser = { version = "0.1.5", package = "fdt" } fdt_parser = { version = "0.1.4", package = "fdt" }
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" } vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }

View File

@@ -111,9 +111,8 @@ pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000);
pub const CMDLINE_MAX_SIZE: usize = 2048; pub const CMDLINE_MAX_SIZE: usize = 2048;
/// FDT is at the beginning of RAM. /// FDT is at the beginning of RAM.
/// Maximum size of the device tree blob as specified in https://www.kernel.org/doc/Documentation/arm64/booting.txt.
pub const FDT_START: GuestAddress = RAM_START; pub const FDT_START: GuestAddress = RAM_START;
/// Maximum size of the device tree blob as specified in [the kernel
/// documentation](https://www.kernel.org/doc/Documentation/arm64/booting.txt).
pub const FDT_MAX_SIZE: u64 = 0x20_0000; pub const FDT_MAX_SIZE: u64 = 0x20_0000;
/// Put ACPI table above dtb /// Put ACPI table above dtb

View File

@@ -16,6 +16,7 @@ use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
use hypervisor::arch::aarch64::gic::Vgic; use hypervisor::arch::aarch64::gic::Vgic;
use log::{log_enabled, Level}; use log::{log_enabled, Level};
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic}; use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};

View File

@@ -1,6 +1,4 @@
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved. // Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::os::fd::AsFd; use std::os::fd::AsFd;

View File

@@ -18,6 +18,9 @@ use std::fmt;
use std::result; use std::result;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
use vm_migration::VersionMapped;
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>; type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>; type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
@@ -45,17 +48,13 @@ pub enum Error {
ModlistSetup(#[source] vm_memory::GuestMemoryError), ModlistSetup(#[source] vm_memory::GuestMemoryError),
#[error("RSDP extends past the end of guest memory")] #[error("RSDP extends past the end of guest memory")]
RsdpPastRamEnd, RsdpPastRamEnd,
#[error("Failed to setup Zero Page for bzImage")]
ZeroPageSetup(#[source] vm_memory::GuestMemoryError),
#[error("Zero Page for bzImage past RAM end")]
ZeroPagePastRamEnd,
} }
/// Type for returning public functions outcome. /// Type for returning public functions outcome.
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
/// Type for memory region types. /// Type for memory region types.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Versionize)]
pub enum RegionType { pub enum RegionType {
/// RAM type /// RAM type
Ram, Ram,
@@ -73,6 +72,8 @@ pub enum RegionType {
Reserved, Reserved,
} }
impl VersionMapped for RegionType {}
/// Module for aarch64 related functionality. /// Module for aarch64 related functionality.
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub mod aarch64; pub mod aarch64;

View File

@@ -17,7 +17,6 @@ use crate::InitramfsConfig;
use crate::RegionType; use crate::RegionType;
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX}; use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError}; use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
use linux_loader::loader::bootparam::{boot_params, setup_header};
use linux_loader::loader::elf::start_info::{ use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
}; };
@@ -64,8 +63,6 @@ pub const _NSIG: i32 = 65;
pub struct EntryPoint { pub struct EntryPoint {
/// Address in guest memory where the guest must start execution /// Address in guest memory where the guest must start execution
pub entry_addr: GuestAddress, pub entry_addr: GuestAddress,
/// This field is used for bzImage to fill the zero page
pub setup_header: Option<setup_header>,
} }
const E820_RAM: u32 = 1; const E820_RAM: u32 = 1;
@@ -183,9 +180,6 @@ pub enum Error {
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API /// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
TdxCapabilities(HypervisorError), TdxCapabilities(HypervisorError),
/// Failed to configure E820 map for bzImage
E820Configuration,
} }
impl From<Error> for super::Error { impl From<Error> for super::Error {
@@ -848,7 +842,8 @@ pub fn configure_vcpu(
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?; regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
if let Some((kernel_entry_point, guest_memory)) = boot_setup { if let Some((kernel_entry_point, guest_memory)) = boot_setup {
regs::setup_regs(vcpu, kernel_entry_point).map_err(Error::RegsConfiguration)?; regs::setup_regs(vcpu, kernel_entry_point.entry_addr.raw_value())
.map_err(Error::RegsConfiguration)?;
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?; regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?; regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
} }
@@ -897,10 +892,8 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
pub fn configure_system( pub fn configure_system(
guest_mem: &GuestMemoryMmap, guest_mem: &GuestMemoryMmap,
cmdline_addr: GuestAddress, cmdline_addr: GuestAddress,
cmdline_size: usize,
initramfs: &Option<InitramfsConfig>, initramfs: &Option<InitramfsConfig>,
_num_cpus: u8, _num_cpus: u8,
setup_header: Option<setup_header>,
rsdp_addr: Option<GuestAddress>, rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>, sgx_epc_region: Option<SgxEpcRegion>,
serial_number: Option<&str>, serial_number: Option<&str>,
@@ -928,31 +921,25 @@ pub fn configure_system(
} }
} }
match setup_header { configure_pvh(
Some(hdr) => configure_32bit_entry( guest_mem,
guest_mem, cmdline_addr,
cmdline_addr, initramfs,
cmdline_size, rsdp_addr,
initramfs, sgx_epc_region,
hdr, )
rsdp_addr,
sgx_epc_region,
),
None => configure_pvh(
guest_mem,
cmdline_addr,
initramfs,
rsdp_addr,
sgx_epc_region,
),
}
} }
type RamRange = (u64, u64); type RamRange = (u64, u64);
/// Returns usable physical memory ranges for the guest /// Returns usable physical memory ranges for the guest
/// These should be used to create e820_RAM memory maps /// These should be used to create e820_RAM memory maps
pub fn generate_ram_ranges(guest_mem: &GuestMemoryMmap) -> super::Result<Vec<RamRange>> { ///
/// There are up to two usable physical memory ranges,
/// divided by the gap at the end of 32bit address space.
pub fn generate_ram_ranges(
guest_mem: &GuestMemoryMmap,
) -> super::Result<(RamRange, Option<RamRange>)> {
// Merge continuous memory regions into one region. // Merge continuous memory regions into one region.
// Note: memory regions from "GuestMemory" are sorted and non-zero sized. // Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = { let ram_regions = {
@@ -985,11 +972,15 @@ pub fn generate_ram_ranges(guest_mem: &GuestMemoryMmap) -> super::Result<Vec<Ram
ram_regions ram_regions
}; };
// Create the memory map entry for memory region before the gap if ram_regions.len() > 2 {
let mut ram_ranges = vec![]; error!(
"There should be up to two usable physical memory ranges, devidided by the
gap at the end of 32bit address space (e.g. between 3G and 4G)."
);
return Err(super::Error::MemmapTableSetup);
}
// Generate the first usable physical memory range before the gap. The e820 map // Generate the first usable physical memory range before the gap
// should only report memory above 1MiB.
let first_ram_range = { let first_ram_range = {
let (first_region_start, first_region_end) = let (first_region_start, first_region_end) =
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?; ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
@@ -1016,19 +1007,33 @@ pub fn generate_ram_ranges(guest_mem: &GuestMemoryMmap) -> super::Result<Vec<Ram
(high_ram_start, *first_region_end) (high_ram_start, *first_region_end)
}; };
ram_ranges.push(first_ram_range);
// Generate additional usable physical memory range after the gap if any. // Generate the second usable physical memory range after the gap if any
for ram_region in ram_regions.iter().skip(1) { let second_ram_range = if let Some((second_region_start, second_region_end)) =
ram_regions.get(1)
{
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
if second_region_start != &ram_64bit_start {
error!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
);
return Err(super::Error::MemmapTableSetup);
}
info!( info!(
"found usable physical memory range, start: 0x{:08x}, end: 0x{:08x}", "Second usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
ram_region.0, ram_region.1 ram_64bit_start, second_region_end
); );
ram_ranges.push(*ram_region); Some((ram_64bit_start, *second_region_end))
} } else {
None
};
Ok(ram_ranges) Ok((first_ram_range, second_ram_range))
} }
fn configure_pvh( fn configure_pvh(
@@ -1079,18 +1084,30 @@ fn configure_pvh(
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM); add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
// Get usable physical memory ranges // Get usable physical memory ranges
let ram_ranges = generate_ram_ranges(guest_mem)?; let (first_ram_range, second_ram_range) = generate_ram_ranges(guest_mem)?;
// Create e820 memory map entries // Create e820 memory map entry before the gap
for ram_range in ram_ranges { info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
first_ram_range.0, first_ram_range.1
);
add_memmap_entry(
&mut memmap,
first_ram_range.0,
first_ram_range.1 - first_ram_range.0,
E820_RAM,
);
// Create e820 memory map after the gap if any
if let Some(second_ram_range) = second_ram_range {
info!( info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}", "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
ram_range.0, ram_range.1 second_ram_range.0, second_ram_range.1
); );
add_memmap_entry( add_memmap_entry(
&mut memmap, &mut memmap,
ram_range.0, second_ram_range.0,
ram_range.1 - ram_range.0, second_ram_range.1 - second_ram_range.0,
E820_RAM, E820_RAM,
); );
} }
@@ -1150,113 +1167,6 @@ fn configure_pvh(
Ok(()) Ok(())
} }
fn configure_32bit_entry(
guest_mem: &GuestMemoryMmap,
cmdline_addr: GuestAddress,
cmdline_size: usize,
initramfs: &Option<InitramfsConfig>,
setup_hdr: setup_header,
rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>,
) -> super::Result<()> {
const KERNEL_LOADER_OTHER: u8 = 0xff;
// Use the provided setup header
let mut params = boot_params {
hdr: setup_hdr,
..Default::default()
};
// Common bootparams settings
if params.hdr.type_of_loader == 0 {
params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
}
params.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
params.hdr.cmdline_size = cmdline_size as u32;
if let Some(initramfs_config) = initramfs {
params.hdr.ramdisk_image = initramfs_config.address.raw_value() as u32;
params.hdr.ramdisk_size = initramfs_config.size as u32;
}
add_e820_entry(&mut params, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
let mem_end = guest_mem.last_addr();
if mem_end < layout::MEM_32BIT_RESERVED_START {
add_e820_entry(
&mut params,
layout::HIGH_RAM_START.raw_value(),
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
E820_RAM,
)?;
} else {
add_e820_entry(
&mut params,
layout::HIGH_RAM_START.raw_value(),
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
E820_RAM,
)?;
if mem_end > layout::RAM_64BIT_START {
add_e820_entry(
&mut params,
layout::RAM_64BIT_START.raw_value(),
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
E820_RAM,
)?;
}
}
add_e820_entry(
&mut params,
layout::PCI_MMCONFIG_START.0,
layout::PCI_MMCONFIG_SIZE,
E820_RESERVED,
)?;
if let Some(sgx_epc_region) = sgx_epc_region {
add_e820_entry(
&mut params,
sgx_epc_region.start().raw_value(),
sgx_epc_region.size(),
E820_RESERVED,
)?;
}
if let Some(rsdp_addr) = rsdp_addr {
params.acpi_rsdp_addr = rsdp_addr.0;
}
let zero_page_addr = layout::ZERO_PAGE_START;
guest_mem
.checked_offset(zero_page_addr, mem::size_of::<boot_params>())
.ok_or(super::Error::ZeroPagePastRamEnd)?;
guest_mem
.write_obj(params, zero_page_addr)
.map_err(super::Error::ZeroPageSetup)?;
Ok(())
}
/// Add an e820 region to the e820 map.
/// Returns Ok(()) if successful, or an error if there is no space left in the map.
fn add_e820_entry(
params: &mut boot_params,
addr: u64,
size: u64,
mem_type: u32,
) -> Result<(), Error> {
if params.e820_entries >= params.e820_table.len() as u8 {
return Err(Error::E820Configuration);
}
params.e820_table[params.e820_entries as usize].addr = addr;
params.e820_table[params.e820_entries as usize].size = size;
params.e820_table[params.e820_entries as usize].type_ = mem_type;
params.e820_entries += 1;
Ok(())
}
fn add_memmap_entry(memmap: &mut Vec<hvm_memmap_table_entry>, addr: u64, size: u64, mem_type: u32) { fn add_memmap_entry(memmap: &mut Vec<hvm_memmap_table_entry>, addr: u64, size: u64, mem_type: u32) {
// Add the table entry to the vector // Add the table entry to the vector
memmap.push(hvm_memmap_table_entry { memmap.push(hvm_memmap_table_entry {
@@ -1503,7 +1413,6 @@ fn update_cpuid_sgx(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use linux_loader::loader::bootparam::boot_e820_entry;
#[test] #[test]
fn regions_base_addr() { fn regions_base_addr() {
@@ -1520,10 +1429,8 @@ mod tests {
let config_err = configure_system( let config_err = configure_system(
&gm, &gm,
GuestAddress(0), GuestAddress(0),
0,
&None, &None,
1, 1,
None,
Some(layout::RSDP_POINTER), Some(layout::RSDP_POINTER),
None, None,
None, None,
@@ -1545,7 +1452,6 @@ mod tests {
configure_system( configure_system(
&gm, &gm,
GuestAddress(0), GuestAddress(0),
0,
&None, &None,
no_vcpus, no_vcpus,
None, None,
@@ -1554,7 +1460,6 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
@@ -1575,7 +1480,6 @@ mod tests {
configure_system( configure_system(
&gm, &gm,
GuestAddress(0), GuestAddress(0),
0,
&None, &None,
no_vcpus, no_vcpus,
None, None,
@@ -1584,14 +1488,12 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
configure_system( configure_system(
&gm, &gm,
GuestAddress(0), GuestAddress(0),
0,
&None, &None,
no_vcpus, no_vcpus,
None, None,
@@ -1600,51 +1502,10 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
} }
#[test]
fn test_add_e820_entry() {
let e820_table = [(boot_e820_entry {
addr: 0x1,
size: 4,
type_: 1,
}); 128];
let expected_params = boot_params {
e820_table,
e820_entries: 1,
..Default::default()
};
let mut params: boot_params = Default::default();
add_e820_entry(
&mut params,
e820_table[0].addr,
e820_table[0].size,
e820_table[0].type_,
)
.unwrap();
assert_eq!(
format!("{:?}", params.e820_table[0]),
format!("{:?}", expected_params.e820_table[0])
);
assert_eq!(params.e820_entries, expected_params.e820_entries);
// Exercise the scenario where the field storing the length of the e820 entry table is
// is bigger than the allocated memory.
params.e820_entries = params.e820_table.len() as u8 + 1;
assert!(add_e820_entry(
&mut params,
e820_table[0].addr,
e820_table[0].size,
e820_table[0].type_
)
.is_err());
}
#[test] #[test]
fn test_add_memmap_entry() { fn test_add_memmap_entry() {
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new(); let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();

View File

@@ -1,6 +1,4 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved. // Copyright 2017 The Chromium OS Authors. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.

View File

@@ -300,7 +300,8 @@ mod tests {
use super::*; use super::*;
use crate::layout::MPTABLE_START; use crate::layout::MPTABLE_START;
use vm_memory::{ use vm_memory::{
bitmap::BitmapSlice, GuestUsize, VolatileMemoryError, VolatileSlice, WriteVolatile, bitmap::BitmapSlice, GuestAddress, GuestUsize, VolatileMemoryError, VolatileSlice,
WriteVolatile,
}; };
fn table_entry_size(type_: u8) -> usize { fn table_entry_size(type_: u8) -> usize {

View File

@@ -6,10 +6,8 @@
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. // 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 // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use crate::layout::{ use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
BOOT_GDT_START, BOOT_IDT_START, BOOT_STACK_POINTER, PVH_INFO_START, ZERO_PAGE_START, use crate::GuestMemoryMmap;
};
use crate::{EntryPoint, GuestMemoryMmap};
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt}; use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
use hypervisor::arch::x86::regs::CR0_PE; use hypervisor::arch::x86::regs::CR0_PE;
use hypervisor::arch::x86::{FpuState, SpecialRegisters, StandardRegisters}; use hypervisor::arch::x86::{FpuState, SpecialRegisters, StandardRegisters};
@@ -79,22 +77,13 @@ pub fn setup_msrs(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> {
/// # Arguments /// # Arguments
/// ///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
/// * `entry_point` - Description of the boot entry to set up. /// * `boot_ip` - Starting instruction pointer.
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, entry_point: EntryPoint) -> Result<()> { pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, boot_ip: u64) -> Result<()> {
let regs = match entry_point.setup_header { let regs = StandardRegisters {
None => StandardRegisters { rflags: 0x0000000000000002u64,
rflags: 0x0000000000000002u64, rbx: PVH_INFO_START.raw_value(),
rip: entry_point.entry_addr.raw_value(), rip: boot_ip,
rbx: PVH_INFO_START.raw_value(), ..Default::default()
..Default::default()
},
Some(_) => StandardRegisters {
rflags: 0x0000000000000002u64,
rip: entry_point.entry_addr.raw_value(),
rsp: BOOT_STACK_POINTER.raw_value(),
rsi: ZERO_PAGE_START.raw_value(),
..Default::default()
},
}; };
vcpu.set_regs(&regs).map_err(Error::SetBaseRegisters) vcpu.set_regs(&regs).map_err(Error::SetBaseRegisters)
} }
@@ -175,6 +164,7 @@ pub fn configure_segments_and_sregs(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::GuestMemoryMmap;
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
fn create_guest_mem() -> GuestMemoryMmap { fn create_guest_mem() -> GuestMemoryMmap {

View File

@@ -9,18 +9,19 @@ default = []
io_uring = ["dep:io-uring"] io_uring = ["dep:io-uring"]
[dependencies] [dependencies]
byteorder = "1.5.0" byteorder = "1.4.3"
crc-any = "2.4.4" crc-any = "2.4.4"
io-uring = { version = "0.6.3", optional = true } io-uring = { version = "0.6.2", optional = true }
libc = "0.2.153" libc = "0.2.147"
log = "0.4.21" log = "0.4.20"
remain = "0.2.13" remain = "0.2.11"
serde = { version = "1.0.197", features = ["derive"] } smallvec = "1.11.0"
smallvec = "1.13.2" thiserror = "1.0.40"
thiserror = "1.0.58" uuid = { version = "1.3.4", features = ["v4"] }
uuid = { version = "1.8.0", features = ["v4"] } versionize = "0.2.0"
virtio-bindings = { version = "0.2.2", features = ["virtio-v5_0_0"] } versionize_derive = "0.1.6"
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.11.0" virtio-queue = "0.11.0"
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"

View File

@@ -37,11 +37,11 @@ use crate::vhdx::{Vhdx, VhdxError};
#[cfg(feature = "io_uring")] #[cfg(feature = "io_uring")]
use io_uring::{opcode, IoUring, Probe}; use io_uring::{opcode, IoUring, Probe};
use libc::{ioctl, S_IFBLK, S_IFMT}; use libc::{ioctl, S_IFBLK, S_IFMT};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::cmp; use std::cmp;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
@@ -53,6 +53,8 @@ use std::sync::Arc;
use std::sync::MutexGuard; use std::sync::MutexGuard;
use std::time::Instant; use std::time::Instant;
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use virtio_bindings::virtio_blk::*; use virtio_bindings::virtio_blk::*;
use virtio_queue::DescriptorChain; use virtio_queue::DescriptorChain;
use vm_memory::{ use vm_memory::{
@@ -543,7 +545,7 @@ impl Request {
} }
} }
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Versionize)]
#[repr(C, packed)] #[repr(C, packed)]
pub struct VirtioBlockConfig { pub struct VirtioBlockConfig {
pub capacity: u64, pub capacity: u64,
@@ -566,7 +568,7 @@ pub struct VirtioBlockConfig {
pub write_zeroes_may_unmap: u8, pub write_zeroes_may_unmap: u8,
pub unused1: [u8; 3], pub unused1: [u8; 3],
} }
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Versionize)]
#[repr(C, packed)] #[repr(C, packed)]
pub struct VirtioBlockGeometry { pub struct VirtioBlockGeometry {
pub cylinders: u16, pub cylinders: u16,

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
mod qcow_raw_file; mod qcow_raw_file;
mod raw_file; mod raw_file;
@@ -1824,6 +1822,7 @@ pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::io::{Read, Seek, SeekFrom, Write};
use vmm_sys_util::tempfile::TempFile; use vmm_sys_util::tempfile::TempFile;
use vmm_sys_util::write_zeroes::WriteZeroes; use vmm_sys_util::write_zeroes::WriteZeroes;

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use super::RawFile; use super::RawFile;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

View File

@@ -11,6 +11,7 @@
use crate::BlockBackend; use crate::BlockBackend;
use libc::c_void; use libc::c_void;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::convert::TryInto;
use std::fs::{File, Metadata}; use std::fs::{File, Metadata};
use std::io::{self, Read, Seek, SeekFrom, Write}; use std::io::{self, Read, Seek, SeekFrom, Write};
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::io; use std::io;

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::collections::hash_map::IterMut; use std::collections::hash_map::IterMut;
use std::collections::HashMap; use std::collections::HashMap;

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::{read_aligned_block_size, DiskTopology}; use crate::{read_aligned_block_size, DiskTopology};
use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};

View File

@@ -7,6 +7,7 @@ extern crate log;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt}; use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use remain::sorted; use remain::sorted;
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write}; use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::size_of; use std::mem::size_of;
@@ -90,7 +91,7 @@ pub type Result<T> = std::result::Result<T, VhdxHeaderError>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FileTypeIdentifier { pub struct FileTypeIdentifier {
pub _signature: u64, pub signature: u64,
} }
impl FileTypeIdentifier { impl FileTypeIdentifier {
@@ -98,14 +99,14 @@ impl FileTypeIdentifier {
pub fn new(f: &mut File) -> Result<FileTypeIdentifier> { pub fn new(f: &mut File) -> Result<FileTypeIdentifier> {
f.seek(SeekFrom::Start(FILE_START)) f.seek(SeekFrom::Start(FILE_START))
.map_err(VhdxHeaderError::SeekFileTypeIdentifier)?; .map_err(VhdxHeaderError::SeekFileTypeIdentifier)?;
let _signature = f let signature = f
.read_u64::<LittleEndian>() .read_u64::<LittleEndian>()
.map_err(VhdxHeaderError::ReadFileTypeIdentifier)?; .map_err(VhdxHeaderError::ReadFileTypeIdentifier)?;
if _signature != VHDX_SIGN { if signature != VHDX_SIGN {
return Err(VhdxHeaderError::InvalidVHDXSign); return Err(VhdxHeaderError::InvalidVHDXSign);
} }
Ok(FileTypeIdentifier { _signature }) Ok(FileTypeIdentifier { signature })
} }
} }
@@ -352,6 +353,12 @@ impl RegionTableEntry {
} }
} }
#[derive(Clone, Debug)]
struct RegionEntry {
_start: u64,
_end: u64,
}
enum HeaderNo { enum HeaderNo {
First, First,
Second, Second,

View File

@@ -6,21 +6,22 @@ edition = "2021"
[dependencies] [dependencies]
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" } acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.81" anyhow = "1.0.75"
arch = { path = "../arch" } arch = { path = "../arch" }
bitflags = "2.5.0" bitflags = "2.4.1"
byteorder = "1.5.0" byteorder = "1.4.3"
event_monitor = { path = "../event_monitor" } event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.153" libc = "0.2.147"
log = "0.4.21" log = "0.4.20"
pci = { path = "../pci" } pci = { path = "../pci" }
serde = { version = "1.0.197", features = ["derive"] } thiserror = "1.0.40"
thiserror = "1.0.58"
tpm = { path = "../tpm" } tpm = { path = "../tpm" }
versionize = "0.2.0"
versionize_derive = "0.1.6"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = "0.14.1" vm-memory = "0.14.0"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"

View File

@@ -1,64 +0,0 @@
// Copyright © 2023 Cyberus Technology
//
// SPDX-License-Identifier: Apache-2.0
//
//! Module for [`DebugconState`].
use std::io;
use std::io::Write;
use std::sync::{Arc, Barrier};
use vm_device::BusDevice;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
/// I/O-port.
pub const DEFAULT_PORT: u64 = 0xe9;
#[derive(Default)]
pub struct DebugconState {}
/// Emulates a debug console similar to the QEMU debugcon device. This device
/// is stateless and only prints the bytes (usually text) that are written to
/// it.
///
/// This device is only available on x86.
///
/// Reference:
/// - https://github.com/qemu/qemu/blob/master/hw/char/debugcon.c
/// - https://phip1611.de/blog/how-to-use-qemus-debugcon-feature-and-write-to-a-file/
pub struct DebugConsole {
id: String,
out: Box<dyn io::Write + Send>,
}
impl DebugConsole {
pub fn new(id: String, out: Box<dyn io::Write + Send>) -> Self {
Self { id, out }
}
}
impl BusDevice for DebugConsole {
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {}
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
if let Err(e) = self.out.write_all(data) {
// unlikely
error!("debug-console: failed writing data: {e:?}");
}
None
}
}
impl Snapshottable for DebugConsole {
fn id(&self) -> String {
self.id.clone()
}
fn snapshot(&mut self) -> Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&())
}
}
impl Pausable for DebugConsole {}
impl Transportable for DebugConsole {}
impl Migratable for DebugConsole {}

View File

@@ -11,16 +11,19 @@
use super::interrupt_controller::{Error, InterruptController}; use super::interrupt_controller::{Error, InterruptController};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
use std::result; use std::result;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup, InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
MsiIrqGroupConfig, MsiIrqSourceConfig, MsiIrqGroupConfig, MsiIrqSourceConfig,
}; };
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
type Result<T> = result::Result<T, Error>; type Result<T> = result::Result<T, Error>;
@@ -133,7 +136,7 @@ pub struct Ioapic {
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct IoapicState { pub struct IoapicState {
id_reg: u32, id_reg: u32,
reg_sel: u32, reg_sel: u32,
@@ -141,6 +144,7 @@ pub struct IoapicState {
used_entries: [bool; NUM_IOAPIC_PINS], used_entries: [bool; NUM_IOAPIC_PINS],
apic_address: u64, apic_address: u64,
} }
impl VersionMapped for IoapicState {}
impl BusDevice for Ioapic { impl BusDevice for Ioapic {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
@@ -440,7 +444,7 @@ impl Snapshottable for Ioapic {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }

View File

@@ -1,8 +1,6 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved. // Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME}; use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
use std::cmp::min; use std::cmp::min;

View File

@@ -8,13 +8,16 @@
//! //!
use crate::{read_le_u32, write_le_u32}; use crate::{read_le_u32, write_le_u32};
use serde::{Deserialize, Serialize};
use std::result; use std::result;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::{fmt, io}; use std::{fmt, io};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
const OFS_DATA: u64 = 0x400; // Data Register const OFS_DATA: u64 = 0x400; // Data Register
const GPIODIR: u64 = 0x400; // Direction Register const GPIODIR: u64 = 0x400; // Direction Register
@@ -86,7 +89,7 @@ pub struct Gpio {
interrupt: Arc<dyn InterruptSourceGroup>, interrupt: Arc<dyn InterruptSourceGroup>,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct GpioState { pub struct GpioState {
data: u32, data: u32,
old_in_data: u32, old_in_data: u32,
@@ -99,6 +102,8 @@ pub struct GpioState {
afsel: u32, afsel: u32,
} }
impl VersionMapped for GpioState {}
impl Gpio { impl Gpio {
/// Constructs an PL061 GPIO device. /// Constructs an PL061 GPIO device.
pub fn new( pub fn new(
@@ -323,7 +328,7 @@ impl Snapshottable for Gpio {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }
@@ -334,6 +339,8 @@ impl Migratable for Gpio {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{read_le_u32, write_le_u32};
use std::sync::Arc;
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig}; use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;

View File

@@ -1,8 +1,6 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved. // Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},

View File

@@ -329,9 +329,10 @@ impl BusDevice for Rtc {
mod tests { mod tests {
use super::*; use super::*;
use crate::{ use crate::{
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16, read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u32, read_le_u64, write_be_u16,
write_be_u32, write_le_i32, write_le_u16, write_le_u64, write_be_u32, write_le_i32, write_le_u16, write_le_u32, write_le_u64,
}; };
use std::sync::Arc;
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig}; use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;

View File

@@ -5,13 +5,16 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use serde::{Deserialize, Serialize};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::{io, result}; use std::{io, result};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
use vmm_sys_util::errno::Result; use vmm_sys_util::errno::Result;
const LOOP_SIZE: usize = 0x40; const LOOP_SIZE: usize = 0x40;
@@ -71,7 +74,7 @@ pub struct Serial {
out: Option<Box<dyn io::Write + Send>>, out: Option<Box<dyn io::Write + Send>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct SerialState { pub struct SerialState {
interrupt_enable: u8, interrupt_enable: u8,
interrupt_identification: u8, interrupt_identification: u8,
@@ -83,6 +86,7 @@ pub struct SerialState {
baud_divisor: u16, baud_divisor: u16,
in_buffer: Vec<u8>, in_buffer: Vec<u8>,
} }
impl VersionMapped for SerialState {}
impl Serial { impl Serial {
pub fn new( pub fn new(
@@ -330,7 +334,7 @@ impl Snapshottable for Serial {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }
@@ -341,7 +345,8 @@ impl Migratable for Serial {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::sync::Mutex; use std::io;
use std::sync::{Arc, Mutex};
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig}; use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;

View File

@@ -7,15 +7,18 @@
//! //!
use crate::{read_le_u32, write_le_u32}; use crate::{read_le_u32, write_le_u32};
use serde::{Deserialize, Serialize};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::time::Instant; use std::time::Instant;
use std::{io, result}; use std::{io, result};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
/* Registers */ /* Registers */
const UARTDR: u64 = 0; const UARTDR: u64 = 0;
@@ -91,7 +94,7 @@ pub struct Pl011 {
timestamp: std::time::Instant, timestamp: std::time::Instant,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct Pl011State { pub struct Pl011State {
flags: u32, flags: u32,
lcr: u32, lcr: u32,
@@ -110,6 +113,8 @@ pub struct Pl011State {
read_trigger: u32, read_trigger: u32,
} }
impl VersionMapped for Pl011State {}
impl Pl011 { impl Pl011 {
/// Constructs an AMBA PL011 UART device. /// Constructs an AMBA PL011 UART device.
pub fn new( pub fn new(
@@ -449,7 +454,7 @@ impl Snapshottable for Pl011 {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }
@@ -460,7 +465,8 @@ impl Migratable for Pl011 {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::sync::Mutex; use std::io;
use std::sync::{Arc, Mutex};
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig}; use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;

View File

@@ -15,8 +15,6 @@ extern crate event_monitor;
extern crate log; extern crate log;
pub mod acpi; pub mod acpi;
#[cfg(target_arch = "x86_64")]
pub mod debug_console;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub mod gic; pub mod gic;
pub mod interrupt_controller; pub mod interrupt_controller;

View File

@@ -9,15 +9,18 @@ use pci::{
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
PCI_CONFIGURATION_ID, PCI_CONFIGURATION_ID,
}; };
use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::result; use std::result;
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::{BusDevice, Resource}; use vm_device::{BusDevice, Resource};
use vm_memory::{Address, GuestAddress}; use vm_memory::{Address, GuestAddress};
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
const PVPANIC_VENDOR_ID: u16 = 0x1b36; const PVPANIC_VENDOR_ID: u16 = 0x1b36;
const PVPANIC_DEVICE_ID: u16 = 0x0011; const PVPANIC_DEVICE_ID: u16 = 0x0011;
@@ -57,20 +60,23 @@ pub struct PvPanicDevice {
bar_regions: Vec<PciBarConfiguration>, bar_regions: Vec<PciBarConfiguration>,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct PvPanicDeviceState { pub struct PvPanicDeviceState {
events: u8, events: u8,
} }
impl VersionMapped for PvPanicDeviceState {}
impl PvPanicDevice { impl PvPanicDevice {
pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> { pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> {
let pci_configuration_state = let pci_configuration_state =
vm_migration::state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID).map_err(|e| { vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
PvPanicError::RetrievePciConfigurationState(anyhow!( .map_err(|e| {
"Failed to get PciConfigurationState from Snapshot: {}", PvPanicError::RetrievePciConfigurationState(anyhow!(
e "Failed to get PciConfigurationState from Snapshot: {}",
)) e
})?; ))
})?;
let mut configuration = PciConfiguration::new( let mut configuration = PciConfiguration::new(
PVPANIC_VENDOR_ID, PVPANIC_VENDOR_ID,
@@ -91,7 +97,7 @@ impl PvPanicDevice {
let state: Option<PvPanicDeviceState> = snapshot let state: Option<PvPanicDeviceState> = snapshot
.as_ref() .as_ref()
.map(|s| s.to_state()) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(|e| { .map_err(|e| {
PvPanicError::CreatePvPanicDevice(anyhow!( PvPanicError::CreatePvPanicDevice(anyhow!(
@@ -204,7 +210,7 @@ impl PciDevice for PvPanicDevice {
} }
bars.push(bar); bars.push(bar);
self.bar_regions.clone_from(&bars); self.bar_regions = bars.clone();
Ok(bars) Ok(bars)
} }
@@ -253,7 +259,7 @@ impl Snapshottable for PvPanicDevice {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut snapshot = Snapshot::new_from_state(&self.state())?; let mut snapshot = Snapshot::new_from_versioned_state(&self.state())?;
// Snapshot PciConfiguration // Snapshot PciConfiguration
snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?); snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);

View File

@@ -1,5 +1,4 @@
All documentations (e.g. files with extension `.md`) in this repository is The documentation in this directory is covered by the following license:
covered by the following license:
Attribution 4.0 International Attribution 4.0 International

View File

@@ -110,7 +110,6 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted | | Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted | | Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
| Inject an NMI | `/vm.nmi` | N/A | N/A | The VM is booted |
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A | | Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) | | Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
@@ -148,7 +147,7 @@ We want to create a virtual machine with the following characteristics:
`/opt/clh/images/focal-server-cloudimg-amd64.raw` `/opt/clh/images/focal-server-cloudimg-amd64.raw`
```shell ```shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i \ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
-X PUT 'http://localhost/api/v1/vm.create' \ -X PUT 'http://localhost/api/v1/vm.create' \
@@ -168,7 +167,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
Once the VM is created, we can boot it: Once the VM is created, we can boot it:
```shell ```shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot' curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
``` ```
@@ -178,7 +177,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
We can fetch information about any VM, as soon as it's created: We can fetch information about any VM, as soon as it's created:
```shell ```shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i \ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
-X GET 'http://localhost/api/v1/vm.info' \ -X GET 'http://localhost/api/v1/vm.info' \
@@ -190,7 +189,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
We can reboot a VM that's already booted: We can reboot a VM that's already booted:
```shell ```shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot' curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
``` ```
@@ -200,7 +199,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
Once booted, we can shut a VM down from the REST API: Once booted, we can shut a VM down from the REST API:
```shell ```shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown' curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
``` ```
@@ -386,7 +385,7 @@ APIs work together, let's look at a complete VM creation flow, from the
[REST API](#rest-api) in order to creates a virtual machine: [REST API](#rest-api) in order to creates a virtual machine:
``` ```
shell shell
#!/usr/bin/env bash #!/bin/bash
curl --unix-socket /tmp/cloud-hypervisor.sock -i \ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
-X PUT 'http://localhost/api/v1/vm.create' \ -X PUT 'http://localhost/api/v1/vm.create' \

View File

@@ -1,16 +1,7 @@
# `cloud-hypervisor` debug IO ports # `cloud-hypervisor` debug IO port
When running x86 guests, `cloud-hypervisor` provides different kinds of debug ports: `cloud-hypervisor` uses the [`0x80`](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
- [`0x80` debug port](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html) I/O port to trace user defined guest events.
- Debug console (by default at `0xe9`).
- Firmware debug port at `0x402`.
All of them can be used to trace user-defined guest events and all of them can
be used simultaneously.
## Debug Ports Overview
### `0x80` I/O port
Whenever the guest write one byte between `0x0` and `0xF` on this particular Whenever the guest write one byte between `0x0` and `0xF` on this particular
I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug` I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug`
@@ -39,7 +30,7 @@ guest will have `cloud-hypervisor` generate timestamped logs of all those steps.
That provides a basic but convenient way of measuring not only the overall guest That provides a basic but convenient way of measuring not only the overall guest
boot time but all intermediate steps as well. boot time but all intermediate steps as well.
#### Logging ## Logging
Assuming parts of the guest software stack have been instrumented to use the Assuming parts of the guest software stack have been instrumented to use the
`cloud-hypervisor` debug I/O port, we may want to gather the related logs. `cloud-hypervisor` debug I/O port, we may want to gather the related logs.
@@ -68,29 +59,3 @@ $ grep "Debug I/O port" /tmp/ch-fw.log
cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds
cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds
``` ```
### Debug console port
The debug console is inspired by QEMU and Bochs, which have a similar feature.
By default, the I/O port `0xe9` is used. This port can be configured like a
console. Thus, it can print to a tty, a file, or a pty, for example.
### Firmware debug port
The firmware debug port is also a simple port that prints all bytes written to
it. The firmware debug port only prints to stdout.
## When do I need these ports?
The ports are on the one hand interesting for firmware or kernel developers, as
they provide an easy way to print debug information from within a guest.
Furthermore, you can patch "normal" software to measure certain events, such as
the boot time of a guest.
## Which port should I choose?
The `0x80` debug port and the port of the firmware debug device are always
available. The debug console must be activated via the command line, but
provides more configuration options.
You can use different ports for different aspect of your logging messages.

View File

@@ -103,7 +103,7 @@ firmware:
### TDShim ### TDShim
> **Note** > **Note**
> The latest version of TDShim being tested is [_v0.8.0_](https://github.com/confidential-containers/td-shim/releases/tag/v0.8.0). > The latest version of TDShim being tested is [_66bb334_](https://github.com/confidential-containers/td-shim/tree/66bb33451befbf1291abe3cfea7ee9e99d922b0d).
This is a lightweight version of the TDVF, written in Rust and designed for This is a lightweight version of the TDVF, written in Rust and designed for
direct kernel boot, which is useful for containers use cases. direct kernel boot, which is useful for containers use cases.
@@ -113,7 +113,7 @@ and `LLVM` first. The TDshim can be build as follows:
```bash ```bash
git clone https://github.com/confidential-containers/td-shim git clone https://github.com/confidential-containers/td-shim
cd td-shim cd td-shim
git checkout v0.8.0 git checkout 66bb33451befbf1291abe3cfea7ee9e99d922b0d
cargo install cargo-xbuild cargo install cargo-xbuild
export CC=clang export CC=clang
export AR=llvm-ar export AR=llvm-ar
@@ -121,13 +121,15 @@ export CC_x86_64_unknown_none=clang
export AR_x86_64_unknown_none=llvm-ar export AR_x86_64_unknown_none=llvm-ar
git submodule update --init --recursive git submodule update --init --recursive
./sh_script/preparation.sh ./sh_script/preparation.sh
cargo image --release cargo xbuild -p td-shim --target x86_64-unknown-none --release --features=main,tdx
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/release/ResetVector.bin target/x86_64-unknown-none/release/td-shim -o target/release/final.bin
``` ```
If debug logs from the TDShim is needed, here are the alternative If debug logs from the TDShim is needed, here are the alternative
commands: commands:
```bash ```bash
cargo image cargo xbuild -p td-shim --target x86_64-unknown-none --features=main,tdx
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/debug/ResetVector.bin target/x86_64-unknown-none/debug/td-shim -o target/debug/final.bin
``` ```
And run a TDX VM by providing the firmware previously built, along with a guest And run a TDX VM by providing the firmware previously built, along with a guest

View File

@@ -42,14 +42,3 @@ actual rate limit users get can be as low as
generally advisable to keep `bw/ops_refill_time` larger than `100 ms` generally advisable to keep `bw/ops_refill_time` larger than `100 ms`
(`cool_down_time`) to make sure the actual rate limit is close to users' (`cool_down_time`) to make sure the actual rate limit is close to users'
expectation ("refill-rate"). expectation ("refill-rate").
## Rate Limit Groups
It is possible to throttle the aggregate bandwidth or operations
of multiple virtio-blk devices using a `rate_limit_group`. virtio-blk devices may be
dynamically added and removed from a `rate_limit_group`. The following example
demonstrates how to throttle the aggregate bandwidth of two disks to 10 MiB/s.
```
--disk path=disk0.raw,rate_limit_group=group0 \
path=disk1.raw,rate_limit_group=group0 \
--rate-limit-group bw_size=1048576,bw_refill_time,bw_refill_time=100
```

View File

@@ -60,7 +60,10 @@ implement a full emulation of a physical IOMMU.
### Kernel ### Kernel
As of Kernel 5.14, virtio-iommu is available for both X86-64 and Aarch64. Since virtio-iommu has landed partially into the version 5.3 of the Linux
kernel, a special branch is needed to get things working with Cloud Hypervisor.
By partially, we are talking about x86 specifically, as it is already fully
functional for ARM architectures.
## Usage ## Usage

View File

@@ -122,64 +122,4 @@ $ ls /sys/kernel/iommu_groups/22/devices/
This means these two devices are under the same IOMMU group 22. In such case, This means these two devices are under the same IOMMU group 22. In such case,
it is important to bind both devices to VFIO and pass them both through the it is important to bind both devices to VFIO and pass them both through the
VM, otherwise this could cause some functional and security issues. VM, otherwise this could cause some functional and security issues.
### Advanced Configuration Options
When using NVIDIA GPUs in a VFIO passthrough configuration, advanced
configuration options are supported to enable GPUDirect P2P DMA over
PCIe. When enabled, loads and stores between GPUs use native PCIe
peer-to-peer transactions instead of a shared memory buffer. This drastically
decreases P2P latency between GPUs. This functionality is supported by
cloud-hypervisor on NVIDIA Turing, Ampere, Hopper, and Lovelace GPUs.
The NVIDIA driver does not enable GPUDirect P2P over PCIe within guests
by default because hardware support for routing P2P TLP between PCIe root
ports is optional. PCIe P2P should always be supported between devices
on the same PCIe switch. The `x_nv_gpudirect_clique` config argument may
be used to signal support for PCIe P2P traffic between NVIDIA VFIO endpoints.
The guest driver assumes that P2P traffic is supported between all endpoints
that are part of the same clique.
```
--device path=/sys/bus/pci/devices/0000:01:00.0/,x_nv_gpudirect_clique=0
```
The following command can be run on the guest to verify that GPUDirect P2P is
correctly enabled.
```
nvidia-smi topo -p2p r
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
GPU0 X OK OK OK OK OK OK OK
GPU1 OK X OK OK OK OK OK OK
GPU2 OK OK X OK OK OK OK OK
GPU3 OK OK OK X OK OK OK OK
GPU4 OK OK OK OK X OK OK OK
GPU5 OK OK OK OK OK X OK OK
GPU6 OK OK OK OK OK OK X OK
GPU7 OK OK OK OK OK OK OK X
```
Some VFIO devices have a 32-bit mmio BAR. When using many such devices, it is
possible to exhaust the 32-bit mmio space available on a PCI segment. The
following example demonstrates an example device with a 16 MiB 32-bit mmio BAR.
```
lspci -s 0000:01:00.0 -v
0000:01:00.0 3D controller: NVIDIA Corporation Device 26b9 (rev a1)
[...]
Memory at f9000000 (32-bit, non-prefetchable) [size=16M]
Memory at 46000000000 (64-bit, prefetchable) [size=64G]
Memory at 48040000000 (64-bit, prefetchable) [size=32M]
[...]
```
When using multiple PCI segments, the 32-bit mmio address space available to
be allocated to VFIO devices is equally split between all PCI segments by
default. This can be tuned with the `--pci-segment` flag. The following example
demonstrates a guest with two PCI segments. 2/3 of the 32-bit mmio address
space is available for use by devices on PCI segment 0 and 1/3 of the 32-bit
mmio address space is available for use by devices on PCI segment 1.
```
--platform num_pci_segments=2
--pci-segment pci_segment=0,mmio32_aperture_weight=2
--pci-segment pci_segment=1,mmio32_aperture_weight=1
```

View File

@@ -2,8 +2,8 @@
The purpose of this document is to illustrate how to test vhost-user-net The purpose of this document is to illustrate how to test vhost-user-net
in cloud-hypervisor with OVS/DPDK as the backend. This document was in cloud-hypervisor with OVS/DPDK as the backend. This document was
tested with Open vSwitch v2.17.8, DPDK v21.11.4, and Cloud Hypervisor tested with Open vSwitch v2.13.1, DPDK v19.11.3, and Cloud Hypervisor
v37.0 on Ubuntu 22.04.3 (host kernel v5.15.0). v15.0 on Ubuntu 20.04.1 (host kernel v5.4.0).
## Framework ## Framework
@@ -74,8 +74,8 @@ Here is an example how to create a bridge and add two DPDK ports to it
# create a bridge # create a bridge
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
# create two DPDK ports and add them to the bridge # create two DPDK ports and add them to the bridge
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user1 ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user2 ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
# set the number of rx queues # set the number of rx queues
ovs-vsctl set Interface vhost-user1 options:n_rxq=2 ovs-vsctl set Interface vhost-user1 options:n_rxq=2
ovs-vsctl set Interface vhost-user2 options:n_rxq=2 ovs-vsctl set Interface vhost-user2 options:n_rxq=2
@@ -92,7 +92,7 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
--kernel vmlinux \ --kernel vmlinux \
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \ --cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
--disk path=focal-server-cloudimg-amd64.raw \ --disk path=focal-server-cloudimg-amd64.raw \
--net mac=52:54:00:02:d9:01,vhost_user=true,socket=/tmp/vhost-user1,num_queues=4,vhost_mode=server --net mac=52:54:00:02:d9:01,vhost_user=true,socket=/var/run/openvswitch/vhost-user1,num_queues=4
# From another terminal. We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host. # From another terminal. We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
./cloud-hypervisor \ ./cloud-hypervisor \
@@ -101,21 +101,21 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
--kernel vmlinux \ --kernel vmlinux \
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \ --cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
--disk path=focal-server-cloudimg-amd64.raw \ --disk path=focal-server-cloudimg-amd64.raw \
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/tmp/vhost-user2,num_queues=4,vhost_mode=server --net mac=52:54:20:11:C5:02,vhost_user=true,socket=/var/run/openvswitch/vhost-user2,num_queues=4
``` ```
_Setup VM1_ _Setup VM1_
```bash ```bash
# From inside the guest # From inside the guest
sudo ip addr add 172.100.0.1/24 dev ens3 sudo ip addr add 172.100.0.1/24 dev ens2
sudo ip link set up dev ens3 sudo ip link set up dev ens2
``` ```
_Setup VM2_ _Setup VM2_
```bash ```bash
# From inside the guest # From inside the guest
sudo ip addr add 172.100.0.2/24 dev ens3 sudo ip addr add 172.100.0.2/24 dev ens2
sudo ip link set up dev ens3 sudo ip link set up dev ens2
``` ```
_Ping VM1 from VM2_ _Ping VM1 from VM2_

View File

@@ -1,6 +1,6 @@
# VSOCK support # VSOCK support
VSOCK provides a way for guest and host to communicate through a socket. `cloud-hypervisor` only supports stream VSOCK sockets. VSOCK provides a way for guest and host to communicate through a socket. VSOCK sockets support both stream and datagram types.
The `virtio-vsock` is based on the [Firecracker](https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md) implementation, where additional details can be found. The `virtio-vsock` is based on the [Firecracker](https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md) implementation, where additional details can be found.

View File

@@ -5,8 +5,8 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
flume = "0.11.0" flume = "0.10.14"
libc = "0.2.153" libc = "0.2.147"
once_cell = "1.19.0" once_cell = "1.18.0"
serde = { version = "1.0.197", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_json = "1.0.115" serde_json = "1.0.107"

361
fuzz/Cargo.lock generated
View File

@@ -5,16 +5,16 @@ version = 3
[[package]] [[package]]
name = "acpi_tables" name = "acpi_tables"
version = "0.1.0" 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#1a733bf690ccc10bdfeacad33e3c9f6cce0008fd"
dependencies = [ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.13" version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@@ -26,9 +26,9 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.6" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
@@ -60,9 +60,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.82" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -79,9 +79,9 @@ checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.1" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]] [[package]]
name = "arch" name = "arch"
@@ -97,6 +97,8 @@ dependencies = [
"serde", "serde",
"thiserror", "thiserror",
"uuid", "uuid",
"versionize",
"versionize_derive",
"vm-fdt", "vm-fdt",
"vm-memory", "vm-memory",
"vm-migration", "vm-migration",
@@ -105,9 +107,18 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.2.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@@ -117,9 +128,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.5.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "block" name = "block"
@@ -131,10 +142,11 @@ dependencies = [
"libc", "libc",
"log", "log",
"remain", "remain",
"serde",
"smallvec", "smallvec",
"thiserror", "thiserror",
"uuid", "uuid",
"versionize",
"versionize_derive",
"virtio-bindings", "virtio-bindings",
"virtio-queue", "virtio-queue",
"vm-memory", "vm-memory",
@@ -144,9 +156,9 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@@ -156,9 +168,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.92" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@@ -172,34 +184,34 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.4" version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
] ]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.2" version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
"clap_lex", "clap_lex",
"strsim 0.11.1", "strsim",
] ]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.7.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "38.0.0" version = "37.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -262,10 +274,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "darling" name = "crc64"
version = "0.20.8" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" checksum = "2707e3afba5e19b75d582d88bc79237418f2a2a2d673d01cf9b03633b46e98f3"
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"darling_macro", "darling_macro",
@@ -273,27 +291,27 @@ dependencies = [
[[package]] [[package]]
name = "darling_core" name = "darling_core"
version = "0.20.8" version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.20.8" version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
@@ -309,16 +327,17 @@ dependencies = [
"acpi_tables", "acpi_tables",
"anyhow", "anyhow",
"arch", "arch",
"bitflags 2.5.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"event_monitor", "event_monitor",
"hypervisor", "hypervisor",
"libc", "libc",
"log", "log",
"pci", "pci",
"serde",
"thiserror", "thiserror",
"tpm", "tpm",
"versionize",
"versionize_derive",
"vm-allocator", "vm-allocator",
"vm-device", "vm-device",
"vm-memory", "vm-memory",
@@ -332,7 +351,7 @@ version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.4.1",
"libc", "libc",
] ]
@@ -355,13 +374,14 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]] [[package]]
name = "flume" name = "flume"
version = "0.11.0" version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"nanorand", "nanorand",
"pin-project",
"spin", "spin",
] ]
@@ -385,9 +405,9 @@ checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.14" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -422,9 +442,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "io-uring" name = "io-uring"
version = "0.6.3" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9febecd4aebbe9c7c23c8e536e966805fdf09944c8a915e7991ee51acb67087" checksum = "460648e47a07a43110fbfa2e0b14afb2be920093c31e5dccc50e49568e099762"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"libc", "libc",
@@ -432,46 +452,45 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.11" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.30" version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2" checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.69" version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]] [[package]]
name = "kvm-bindings" name = "kvm-bindings"
version = "0.8.1" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-live-upgrade-stable-37.x#f03fc575cdf20c3af9ca3d4d203f171943d95be4"
checksum = "a82e7e8725a39a0015e511a46cc1f7d90cecc180db1610c4d0d4339a9e48bd21"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive",
"vmm-sys-util", "vmm-sys-util",
"zerocopy",
] ]
[[package]] [[package]]
name = "kvm-ioctls" name = "kvm-ioctls"
version = "0.17.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bedae2ca4a531bebe311abaf9691f5cc14eaa21475243caa2e39c43bb872947d" checksum = "9002dff009755414f22b962ec6ae6980b07d6d8b06e5297b1062019d72bd6a8c"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.4.1",
"kvm-bindings", "kvm-bindings",
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -479,9 +498,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -515,14 +534,14 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.21" version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#ef43cef7162a55a6790d528a5e76b4fe2da22de0" source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#e75dfa1eeea23b69caa7407bc2c3a76d7b7262fb"
dependencies = [ dependencies = [
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -556,6 +575,8 @@ dependencies = [
"rate_limiter", "rate_limiter",
"serde", "serde",
"thiserror", "thiserror",
"versionize",
"versionize_derive",
"virtio-bindings", "virtio-bindings",
"virtio-queue", "virtio-queue",
"vm-memory", "vm-memory",
@@ -584,6 +605,8 @@ dependencies = [
"log", "log",
"serde", "serde",
"thiserror", "thiserror",
"versionize",
"versionize_derive",
"vfio-bindings", "vfio-bindings",
"vfio-ioctls", "vfio-ioctls",
"vfio_user", "vfio_user",
@@ -595,19 +618,39 @@ dependencies = [
] ]
[[package]] [[package]]
name = "proc-macro2" name = "pin-project"
version = "1.0.81" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.47",
]
[[package]]
name = "proc-macro2"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.36" version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -616,7 +659,6 @@ dependencies = [
name = "rate_limiter" name = "rate_limiter"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"epoll",
"libc", "libc",
"log", "log",
"thiserror", "thiserror",
@@ -625,20 +667,20 @@ dependencies = [
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.13" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad9f2390298a947ee0aa6073d440e221c0726188cfbcdf9604addb6ee393eb4a" checksum = "1ad5e011230cad274d0532460c5ab69828ea47ae75681b42a841663efffaf794"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.17" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@@ -657,29 +699,29 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.198" version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.198" version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.115" version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -688,25 +730,24 @@ dependencies = [
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.8.0" version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive",
"serde_with_macros", "serde_with_macros",
] ]
[[package]] [[package]]
name = "serde_with_macros" name = "serde_with_macros"
version = "3.8.0" version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
@@ -725,18 +766,18 @@ dependencies = [
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.2" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.13.2" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
[[package]] [[package]]
name = "spin" name = "spin"
@@ -754,16 +795,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "strsim" name = "syn"
version = "0.11.1" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.58" version = "2.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -772,22 +818,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.58" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.58" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
] ]
[[package]] [[package]]
@@ -828,17 +874,44 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.8.0" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "versionize"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62929d59c7f6730b7298fcb363760550f4db6e353fbac4076d447d0e82799d6d"
dependencies = [
"bincode",
"crc64",
"proc-macro2",
"quote",
"serde",
"serde_derive",
"syn 1.0.109",
"versionize_derive",
"vmm-sys-util",
]
[[package]]
name = "versionize_derive"
version = "0.1.6"
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch-0.1.6#7906da996152e2d0ab08f5526440683bf3ca7834"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "vfio-bindings" name = "vfio-bindings"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#da8c5b67095fb70f5ef237ca63d316219888f015" source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a"
dependencies = [ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
@@ -846,7 +919,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio-ioctls" name = "vfio-ioctls"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#da8c5b67095fb70f5ef237ca63d316219888f015" source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"kvm-bindings", "kvm-bindings",
@@ -882,7 +955,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b64e816d0d49769fbfaa1494eb77cc2a3ddc526ead05c7f922cb7d64106286f" checksum = "2b64e816d0d49769fbfaa1494eb77cc2a3ddc526ead05c7f922cb7d64106286f"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.4.1",
"libc", "libc",
"vm-memory", "vm-memory",
"vmm-sys-util", "vmm-sys-util",
@@ -913,9 +986,10 @@ dependencies = [
"seccompiler", "seccompiler",
"serde", "serde",
"serde_json", "serde_json",
"serde_with",
"serial_buffer", "serial_buffer",
"thiserror", "thiserror",
"versionize",
"versionize_derive",
"vhost", "vhost",
"virtio-bindings", "virtio-bindings",
"virtio-queue", "virtio-queue",
@@ -963,14 +1037,14 @@ dependencies = [
[[package]] [[package]]
name = "vm-fdt" name = "vm-fdt"
version = "0.3.0" version = "0.2.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#982fb8d9c8cd7f53520d7e304b39ff307fa3a641" source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927d19b50c85fcd5ce904a8c"
[[package]] [[package]]
name = "vm-memory" name = "vm-memory"
version = "0.14.1" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4" checksum = "74ffc42216c32c35f858fa4bfdcd9b61017dfd691e0240268fdc85dbf59e5459"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"libc", "libc",
@@ -986,6 +1060,8 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
"versionize",
"versionize_derive",
"vm-memory", "vm-memory",
] ]
@@ -1006,7 +1082,7 @@ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
"arch", "arch",
"bitflags 2.5.0", "bitflags 2.4.1",
"block", "block",
"cfg-if", "cfg-if",
"clap", "clap",
@@ -1023,7 +1099,6 @@ dependencies = [
"once_cell", "once_cell",
"option_parser", "option_parser",
"pci", "pci",
"rate_limiter",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_json", "serde_json",
@@ -1032,6 +1107,8 @@ dependencies = [
"thiserror", "thiserror",
"tracer", "tracer",
"uuid", "uuid",
"versionize",
"versionize_derive",
"vfio-ioctls", "vfio-ioctls",
"vfio_user", "vfio_user",
"virtio-devices", "virtio-devices",
@@ -1065,9 +1142,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.92" version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@@ -1075,24 +1152,24 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.92" version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.92" version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -1100,22 +1177,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.92" version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.92" version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
[[package]] [[package]]
name = "winapi" name = "winapi"
@@ -1150,9 +1227,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.4" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
@@ -1165,45 +1242,45 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.4" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.4" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.5" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.5" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.5" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.5" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.5" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
@@ -1223,5 +1300,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.47",
] ]

View File

@@ -14,8 +14,8 @@ igvm = []
[dependencies] [dependencies]
block = { path = "../block" } block = { path = "../block" }
devices = { path = "../devices" } devices = { path = "../devices" }
epoll = "4.3.3" epoll = "4.3.1"
libc = "0.2.153" libc = "0.2.152"
libfuzzer-sys = "0.4.7" libfuzzer-sys = "0.4.7"
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] } linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
@@ -26,7 +26,7 @@ virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.11.0" virtio-queue = "0.11.0"
vmm = { path = "../vmm" } vmm = { path = "../vmm" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"
vm-memory = "0.14.1" vm-memory = "0.14.0"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
@@ -34,6 +34,10 @@ vm-virtio = { path = "../vm-virtio" }
[dependencies.cloud-hypervisor] [dependencies.cloud-hypervisor]
path = ".." path = ".."
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" }
# Prevent this from interfering with workspaces # Prevent this from interfering with workspaces
[workspace] [workspace]
members = ["."] members = ["."]

View File

@@ -21,7 +21,6 @@ use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT}; use virtio_queue::{Queue, QueueT};
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic}; use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
use std::collections::BTreeMap;
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>; type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
@@ -50,7 +49,6 @@ fuzz_target!(|bytes| {
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap(); let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
let disk_file: File = unsafe { File::from_raw_fd(shm) }; let disk_file: File = unsafe { File::from_raw_fd(shm) };
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>; let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
let queue_affinity = BTreeMap::new();
let mut block = Block::new( let mut block = Block::new(
"tmp".to_owned(), "tmp".to_owned(),
qcow_disk, qcow_disk,
@@ -64,7 +62,6 @@ fuzz_target!(|bytes| {
None, None,
EventFd::new(EFD_NONBLOCK).unwrap(), EventFd::new(EFD_NONBLOCK).unwrap(),
None, None,
queue_affinity,
) )
.unwrap(); .unwrap();

View File

@@ -6,6 +6,8 @@
use devices::legacy::Cmos; use devices::legacy::Cmos;
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use vm_device::BusDevice; use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;

View File

@@ -7,18 +7,9 @@ use libfuzzer_sys::fuzz_target;
use micro_http::Request; use micro_http::Request;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};
use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use vm_migration::MigratableError; use vmm::api::{http::*, ApiRequest, ApiResponsePayload};
use vmm::api::{
http::*, ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
VmSendMigrationData, VmmPingResponse,
};
use vmm::config::RestoreConfig;
use vmm::vm::{Error as VmError, VmState};
use vmm::vm_config::*;
use vmm::{EpollContext, EpollDispatch}; use vmm::{EpollContext, EpollDispatch};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@@ -78,208 +69,6 @@ fn generate_request(bytes: &[u8]) -> Option<Request> {
Request::try_from(&request, None).ok() Request::try_from(&request, None).ok()
} }
struct StubApiRequestHandler;
impl RequestHandler for StubApiRequestHandler {
fn vm_create(&mut self, _: Arc<Mutex<VmConfig>>) -> Result<(), VmError> {
Ok(())
}
fn vm_boot(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_pause(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_resume(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> {
Ok(())
}
fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> {
Ok(())
}
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> {
Ok(())
}
fn vm_shutdown(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_reboot(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_info(&self) -> Result<VmInfoResponse, VmError> {
Ok(VmInfoResponse {
config: Arc::new(Mutex::new(VmConfig {
cpus: CpusConfig {
boot_vcpus: 1,
max_vcpus: 1,
topology: None,
kvm_hyperv: false,
max_phys_bits: 46,
affinity: None,
features: CpuFeatures::default(),
},
memory: MemoryConfig {
size: 536_870_912,
mergeable: false,
hotplug_method: HotplugMethod::Acpi,
hotplug_size: None,
hotplugged_size: None,
shared: false,
hugepages: false,
hugepage_size: None,
prefault: false,
zones: None,
thp: true,
},
payload: Some(PayloadConfig {
kernel: Some(PathBuf::from("/path/to/kernel")),
firmware: None,
cmdline: None,
initramfs: None,
#[cfg(feature = "igvm")]
igvm: None,
}),
rate_limit_groups: None,
disks: None,
net: None,
rng: RngConfig {
src: PathBuf::from("/dev/urandom"),
iommu: false,
},
balloon: None,
fs: None,
pmem: None,
serial: ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Null,
iommu: false,
socket: None,
},
console: ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Tty,
iommu: false,
socket: None,
},
#[cfg(target_arch = "x86_64")]
debug_console: DebugConsoleConfig::default(),
devices: None,
user_devices: None,
vdpa: None,
vsock: None,
pvpanic: false,
iommu: false,
#[cfg(target_arch = "x86_64")]
sgx_epc: None,
numa: None,
watchdog: false,
#[cfg(feature = "guest_debug")]
gdb: false,
pci_segments: None,
platform: None,
tpm: None,
preserved_fds: None,
})),
state: VmState::Running,
memory_actual_size: 0,
device_tree: None,
})
}
fn vmm_ping(&self) -> VmmPingResponse {
VmmPingResponse {
build_version: String::new(),
version: String::new(),
pid: 0,
features: Vec::new(),
}
}
fn vm_delete(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vmm_shutdown(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> {
Ok(())
}
fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> {
Ok(())
}
fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> {
Ok(())
}
fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> {
Ok(None)
}
fn vm_power_button(&mut self) -> Result<(), VmError> {
Ok(())
}
fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> {
Ok(())
}
fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
Ok(())
}
fn vm_nmi(&mut self) -> Result<(), VmError> {
Ok(())
}
}
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) { fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
let mut epoll = EpollContext::new().unwrap(); let mut epoll = EpollContext::new().unwrap();
epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap(); epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
@@ -309,7 +98,89 @@ fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receive
EpollDispatch::Api => { EpollDispatch::Api => {
for _ in 0..api_evt.read().unwrap() { for _ in 0..api_evt.read().unwrap() {
let api_request = api_receiver.recv().unwrap(); let api_request = api_receiver.recv().unwrap();
api_request(&mut StubApiRequestHandler).unwrap(); match api_request {
ApiRequest::VmCreate(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmDelete(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmBoot(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmShutdown(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmReboot(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmInfo(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmmPing(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmPause(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmResume(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmSnapshot(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmRestore(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmmShutdown(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmResize(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmResizeZone(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddDevice(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddUserDevice(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmRemoveDevice(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddDisk(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddFs(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddPmem(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddNet(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddVdpa(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmAddVsock(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmCounters(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmReceiveMigration(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmSendMigration(_, sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
ApiRequest::VmPowerButton(sender) => {
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
}
}
} }
} }
_ => { _ => {

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
#![no_main] #![no_main]
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;

View File

@@ -12,28 +12,28 @@ sev_snp = ["igvm_parser", "igvm_defs"]
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.81" anyhow = "1.0.75"
byteorder = "1.5.0" byteorder = "1.4.3"
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true } igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true }
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true } igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true }
libc = "0.2.153" libc = "0.2.147"
log = "0.4.21" log = "0.4.20"
kvm-bindings = { version = "0.8.1", optional = true, features = ["serde"] } kvm-ioctls = { version = "0.16.0", optional = true }
kvm-ioctls = { version = "0.17.0", optional = true } kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true } mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true} mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.197", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_with = { version = "3.7.0", default-features = false, features = ["macros"] } serde_with = { version = "3.4.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] } vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] } vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
thiserror = "1.0.58" thiserror = "1.0.52"
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86] [target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
optional = true optional = true
version = "1.21.0" version = "1.20.0"
default-features = false default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"] features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
[dev-dependencies] [dev-dependencies]
env_logger = "0.11.3" env_logger = "0.10.0"

View File

@@ -1,6 +1,4 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved. // Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
use crate::{CpuState, GicState, HypervisorDeviceError, HypervisorVmError}; use crate::{CpuState, GicState, HypervisorDeviceError, HypervisorVmError};
use std::any::Any; use std::any::Any;

View File

@@ -1,5 +1,3 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved. // Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
pub mod gic; pub mod gic;

View File

@@ -10,8 +10,10 @@
// CMP-Compare Two Operands // CMP-Compare Two Operands
// //
use crate::arch::emulator::{EmulationError, PlatformEmulator};
use crate::arch::x86::emulator::instructions::*; use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::regs::*; use crate::arch::x86::regs::*;
use crate::arch::x86::Exception;
// CMP affects OF, SF, ZF, AF, PF and CF // CMP affects OF, SF, ZF, AF, PF and CF
const FLAGS_MASK: u64 = CF | PF | AF | ZF | SF | OF; const FLAGS_MASK: u64 = CF | PF | AF | ZF | SF | OF;
@@ -209,6 +211,8 @@ impl<T: CpuStateManager> InstructionHandler<T> for Cmp_rm64_imm8 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::mock_vmm::*; use crate::arch::x86::emulator::mock_vmm::*;

View File

@@ -12,7 +12,9 @@
// Copies the second operand (source operand) to the first operand (destination operand). // Copies the second operand (source operand) to the first operand (destination operand).
// //
use crate::arch::emulator::{EmulationError, PlatformEmulator};
use crate::arch::x86::emulator::instructions::*; use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::Exception;
macro_rules! mov_rm_r { macro_rules! mov_rm_r {
($bound:ty) => { ($bound:ty) => {
@@ -269,6 +271,7 @@ impl<T: CpuStateManager> InstructionHandler<T> for Mov_RAX_moffs64 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::mock_vmm::*; use crate::arch::x86::emulator::mock_vmm::*;

View File

@@ -10,8 +10,10 @@
// MOVS - Move Data from String to String // MOVS - Move Data from String to String
// //
use crate::arch::emulator::{EmulationError, PlatformEmulator};
use crate::arch::x86::emulator::instructions::*; use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::regs::DF; use crate::arch::x86::regs::DF;
use crate::arch::x86::Exception;
macro_rules! movs { macro_rules! movs {
($bound:ty) => { ($bound:ty) => {
@@ -100,6 +102,7 @@ impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::mock_vmm::*; use crate::arch::x86::emulator::mock_vmm::*;

View File

@@ -10,7 +10,9 @@
// OR - Logical inclusive OR // OR - Logical inclusive OR
// //
use crate::arch::emulator::{EmulationError, PlatformEmulator};
use crate::arch::x86::emulator::instructions::*; use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::Exception;
macro_rules! or_rm_r { macro_rules! or_rm_r {
($bound:ty) => { ($bound:ty) => {
@@ -50,6 +52,7 @@ impl<T: CpuStateManager> InstructionHandler<T> for Or_rm8_r8 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::mock_vmm::*; use crate::arch::x86::emulator::mock_vmm::*;

View File

@@ -648,9 +648,13 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
#[cfg(test)] #[cfg(test)]
mod mock_vmm { mod mock_vmm {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::EmulatorCpuState as CpuState; use crate::arch::emulator::{EmulationError, PlatformEmulator};
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt}; use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
use crate::arch::x86::Exception;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -768,6 +772,7 @@ mod mock_vmm {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)]
use super::*; use super::*;
use crate::arch::x86::emulator::mock_vmm::*; use crate::arch::x86::emulator::mock_vmm::*;

View File

@@ -312,10 +312,10 @@ pub struct MsrEntry {
pub data: u64, pub data: u64,
} }
#[repr(C)]
#[serde_with::serde_as] #[serde_with::serde_as]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone)]
pub struct XsaveState { pub struct XsaveState {
#[serde_as(as = "[_; 1024usize]")]
pub region: [u32; 1024usize], pub region: [u32; 1024usize],
} }
@@ -325,3 +325,26 @@ impl Default for XsaveState {
unsafe { ::std::mem::zeroed() } unsafe { ::std::mem::zeroed() }
} }
} }
impl<'de> serde::Deserialize<'de> for XsaveState {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let region: Vec<u32> = Vec::deserialize(deserializer)?;
let mut val: XsaveState = XsaveState::default();
// This panics if the source and destination have different lengths.
val.region.copy_from_slice(&region[..]);
Ok(val)
}
}
impl serde::Serialize for XsaveState {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let region = &self.region[..];
region.serialize(serializer)
}
}

View File

@@ -1,6 +1,4 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved. // Copyright 2017 The Chromium OS Authors. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.

View File

@@ -107,28 +107,14 @@ pub enum HypervisorCpuError {
/// ///
/// Setting Saved Processor Extended States error /// Setting Saved Processor Extended States error
/// ///
#[cfg(feature = "kvm")]
#[error("Failed to set Saved Processor Extended States: {0}")] #[error("Failed to set Saved Processor Extended States: {0}")]
SetXsaveState(#[source] anyhow::Error), SetXsaveState(#[source] anyhow::Error),
/// ///
/// Getting Saved Processor Extended States error /// Getting Saved Processor Extended States error
/// ///
#[cfg(feature = "kvm")]
#[error("Failed to get Saved Processor Extended States: {0}")] #[error("Failed to get Saved Processor Extended States: {0}")]
GetXsaveState(#[source] anyhow::Error), GetXsaveState(#[source] anyhow::Error),
/// ///
/// Getting the VP state components error
///
#[cfg(feature = "mshv")]
#[error("Failed to get VP State Components: {0}")]
GetAllVpStateComponents(#[source] anyhow::Error),
///
/// Setting the VP state components error
///
#[cfg(feature = "mshv")]
#[error("Failed to set VP State Components: {0}")]
SetAllVpStateComponents(#[source] anyhow::Error),
///
/// Setting Extended Control Registers error /// Setting Extended Control Registers error
/// ///
#[error("Failed to set Extended Control Registers: {0}")] #[error("Failed to set Extended Control Registers: {0}")]
@@ -286,23 +272,18 @@ pub enum HypervisorCpuError {
/// ///
#[error("Failed to get CPUID entries: {0}")] #[error("Failed to get CPUID entries: {0}")]
GetCpuidVales(#[source] anyhow::Error), GetCpuidVales(#[source] anyhow::Error),
///
/// Setting SEV control register error
///
#[cfg(feature = "sev_snp")]
#[error("Failed to set sev control register: {0}")]
SetSevControlRegister(#[source] anyhow::Error),
/// Error injecting NMI
///
#[error("Failed to inject NMI")]
Nmi(#[source] anyhow::Error),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum VmExit { pub enum VmExit<'a> {
#[cfg(target_arch = "x86_64")]
IoOut(u16 /* port */, &'a [u8] /* data */),
#[cfg(target_arch = "x86_64")]
IoIn(u16 /* port */, &'a mut [u8] /* data */),
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
IoapicEoi(u8 /* vector */), IoapicEoi(u8 /* vector */),
MmioRead(u64 /* address */, &'a mut [u8]),
MmioWrite(u64 /* address */, &'a [u8]),
Ignore, Ignore,
Reset, Reset,
Shutdown, Shutdown,
@@ -514,14 +495,4 @@ pub trait Vcpu: Send + Sync {
) -> Result<[u32; 4]> { ) -> Result<[u32; 4]> {
unimplemented!() unimplemented!()
} }
#[cfg(feature = "mshv")]
fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
unimplemented!()
}
#[cfg(target_arch = "x86_64")]
///
/// Trigger NMI interrupt
///
fn nmi(&self) -> Result<()>;
} }

View File

@@ -21,6 +21,8 @@ use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
///
///
pub enum HypervisorError { pub enum HypervisorError {
/// ///
/// Hypervisor availability check error /// Hypervisor availability check error

View File

@@ -1,6 +1,4 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved. // Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
mod dist_regs; mod dist_regs;
mod icc_regs; mod icc_regs;
@@ -8,7 +6,7 @@ mod redist_regs;
use crate::arch::aarch64::gic::{Error, Result, Vgic, VgicConfig}; use crate::arch::aarch64::gic::{Error, Result, Vgic, VgicConfig};
use crate::device::HypervisorDeviceError; use crate::device::HypervisorDeviceError;
use crate::kvm::KvmVm; use crate::kvm::{kvm_bindings, KvmVm};
use crate::{CpuState, Vm}; use crate::{CpuState, Vm};
use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr}; use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
use icc_regs::{get_icc_regs, set_icc_regs}; use icc_regs::{get_icc_regs, set_icc_regs};
@@ -16,6 +14,7 @@ use kvm_ioctls::DeviceFd;
use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs}; use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::convert::TryInto;
const GITS_CTLR: u32 = 0x0000; const GITS_CTLR: u32 = 0x0000;
const GITS_IIDR: u32 = 0x0004; const GITS_IIDR: u32 = 0x0004;

View File

@@ -27,6 +27,8 @@ use crate::{arm64_core_reg_id, offset_of};
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd}; use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(target_arch = "aarch64")]
use std::convert::TryInto;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::fs::File; use std::fs::File;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -36,6 +38,7 @@ use std::os::unix::io::RawFd;
use std::result; use std::result;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(target_arch = "aarch64")]
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@@ -102,15 +105,6 @@ pub use {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196; const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
#[cfg(target_arch = "x86_64")]
use vmm_sys_util::ioctl_io_nr;
#[cfg(all(not(feature = "tdx"), target_arch = "x86_64"))]
use vmm_sys_util::ioctl_ioc_nr;
#[cfg(target_arch = "x86_64")]
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
const KVM_EXIT_TDX: u32 = 50; const KVM_EXIT_TDX: u32 = 50;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
@@ -321,7 +315,7 @@ impl From<CpuState> for VcpuKvmState {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
impl From<kvm_clock_data> for ClockData { impl From<kvm_clock_data> for ClockData {
fn from(d: kvm_clock_data) -> Self { fn from(d: kvm_clock_data) -> Self {
ClockData::Kvm(d) ClockData::Kvm(d.into())
} }
} }
@@ -329,7 +323,7 @@ impl From<kvm_clock_data> for ClockData {
impl From<ClockData> for kvm_clock_data { impl From<ClockData> for kvm_clock_data {
fn from(ms: ClockData) -> Self { fn from(ms: ClockData) -> Self {
match ms { match ms {
ClockData::Kvm(s) => s, ClockData::Kvm(s) => s.into(),
/* Needed in case other hypervisors are enabled */ /* Needed in case other hypervisors are enabled */
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
_ => panic!("CpuState is not valid"), _ => panic!("CpuState is not valid"),
@@ -454,12 +448,12 @@ impl vm::Vm for KvmVm {
id: u8, id: u8,
vm_ops: Option<Arc<dyn VmOps>>, vm_ops: Option<Arc<dyn VmOps>>,
) -> vm::Result<Arc<dyn cpu::Vcpu>> { ) -> vm::Result<Arc<dyn cpu::Vcpu>> {
let fd = self let vc = self
.fd .fd
.create_vcpu(id as u64) .create_vcpu(id as u64)
.map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?; .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
let vcpu = KvmVcpu { let vcpu = KvmVcpu {
fd: Arc::new(Mutex::new(fd)), fd: vc,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
msrs: self.msrs.clone(), msrs: self.msrs.clone(),
vm_ops, vm_ops,
@@ -1169,7 +1163,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
/// Vcpu struct for KVM /// Vcpu struct for KVM
pub struct KvmVcpu { pub struct KvmVcpu {
fd: Arc<Mutex<VcpuFd>>, fd: VcpuFd,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
msrs: Vec<MsrEntry>, msrs: Vec<MsrEntry>,
vm_ops: Option<Arc<dyn vm::VmOps>>, vm_ops: Option<Arc<dyn vm::VmOps>>,
@@ -1197,8 +1191,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_regs(&self) -> cpu::Result<StandardRegisters> { fn get_regs(&self) -> cpu::Result<StandardRegisters> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_regs() .get_regs()
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
.into()) .into())
@@ -1220,8 +1212,6 @@ impl cpu::Vcpu for KvmVcpu {
for i in 0..31 { for i in 0..31 {
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.regs.regs[i] = u64::from_le_bytes(bytes); state.regs.regs[i] = u64::from_le_bytes(bytes);
@@ -1233,8 +1223,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, sp); let off = offset_of!(user_pt_regs, sp);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.regs.sp = u64::from_le_bytes(bytes); state.regs.sp = u64::from_le_bytes(bytes);
@@ -1243,8 +1231,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, pc); let off = offset_of!(user_pt_regs, pc);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.regs.pc = u64::from_le_bytes(bytes); state.regs.pc = u64::from_le_bytes(bytes);
@@ -1253,8 +1239,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, pstate); let off = offset_of!(user_pt_regs, pstate);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.regs.pstate = u64::from_le_bytes(bytes); state.regs.pstate = u64::from_le_bytes(bytes);
@@ -1263,8 +1247,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, sp_el1); let off = offset_of!(kvm_regs, sp_el1);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.sp_el1 = u64::from_le_bytes(bytes); state.sp_el1 = u64::from_le_bytes(bytes);
@@ -1274,8 +1256,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, elr_el1); let off = offset_of!(kvm_regs, elr_el1);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.elr_el1 = u64::from_le_bytes(bytes); state.elr_el1 = u64::from_le_bytes(bytes);
@@ -1285,8 +1265,6 @@ impl cpu::Vcpu for KvmVcpu {
for i in 0..KVM_NR_SPSR as usize { for i in 0..KVM_NR_SPSR as usize {
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.spsr[i] = u64::from_le_bytes(bytes); state.spsr[i] = u64::from_le_bytes(bytes);
@@ -1299,8 +1277,6 @@ impl cpu::Vcpu for KvmVcpu {
for i in 0..32 { for i in 0..32 {
let mut bytes = [0_u8; 16]; let mut bytes = [0_u8; 16];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.fp_regs.vregs[i] = u128::from_le_bytes(bytes); state.fp_regs.vregs[i] = u128::from_le_bytes(bytes);
@@ -1311,8 +1287,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
let mut bytes = [0_u8; 4]; let mut bytes = [0_u8; 4];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.fp_regs.fpsr = u32::from_le_bytes(bytes); state.fp_regs.fpsr = u32::from_le_bytes(bytes);
@@ -1321,8 +1295,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
let mut bytes = [0_u8; 4]; let mut bytes = [0_u8; 4];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.fp_regs.fpcr = u32::from_le_bytes(bytes); state.fp_regs.fpcr = u32::from_le_bytes(bytes);
@@ -1336,8 +1308,6 @@ impl cpu::Vcpu for KvmVcpu {
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> { fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
let regs = (*regs).into(); let regs = (*regs).into();
self.fd self.fd
.lock()
.unwrap()
.set_regs(&regs) .set_regs(&regs)
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
} }
@@ -1354,8 +1324,6 @@ impl cpu::Vcpu for KvmVcpu {
let mut off = offset_of!(user_pt_regs, regs); let mut off = offset_of!(user_pt_regs, regs);
for i in 0..31 { for i in 0..31 {
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.regs[i].to_le_bytes(), &state.regs.regs[i].to_le_bytes(),
@@ -1366,8 +1334,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, sp); let off = offset_of!(user_pt_regs, sp);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.sp.to_le_bytes(), &state.regs.sp.to_le_bytes(),
@@ -1376,8 +1342,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, pc); let off = offset_of!(user_pt_regs, pc);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.pc.to_le_bytes(), &state.regs.pc.to_le_bytes(),
@@ -1386,8 +1350,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(user_pt_regs, pstate); let off = offset_of!(user_pt_regs, pstate);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.pstate.to_le_bytes(), &state.regs.pstate.to_le_bytes(),
@@ -1396,8 +1358,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, sp_el1); let off = offset_of!(kvm_regs, sp_el1);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.sp_el1.to_le_bytes(), &state.sp_el1.to_le_bytes(),
@@ -1406,8 +1366,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, elr_el1); let off = offset_of!(kvm_regs, elr_el1);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.elr_el1.to_le_bytes(), &state.elr_el1.to_le_bytes(),
@@ -1417,8 +1375,6 @@ impl cpu::Vcpu for KvmVcpu {
let mut off = offset_of!(kvm_regs, spsr); let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize { for i in 0..KVM_NR_SPSR as usize {
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.spsr[i].to_le_bytes(), &state.spsr[i].to_le_bytes(),
@@ -1430,8 +1386,6 @@ impl cpu::Vcpu for KvmVcpu {
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs); let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 { for i in 0..32 {
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U128, off), arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
&state.fp_regs.vregs[i].to_le_bytes(), &state.fp_regs.vregs[i].to_le_bytes(),
@@ -1442,8 +1396,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off), arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
&state.fp_regs.fpsr.to_le_bytes(), &state.fp_regs.fpsr.to_le_bytes(),
@@ -1452,8 +1404,6 @@ impl cpu::Vcpu for KvmVcpu {
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off), arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
&state.fp_regs.fpcr.to_le_bytes(), &state.fp_regs.fpcr.to_le_bytes(),
@@ -1469,8 +1419,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_sregs(&self) -> cpu::Result<SpecialRegisters> { fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_sregs() .get_sregs()
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
.into()) .into())
@@ -1483,8 +1431,6 @@ impl cpu::Vcpu for KvmVcpu {
fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> { fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
let sregs = (*sregs).into(); let sregs = (*sregs).into();
self.fd self.fd
.lock()
.unwrap()
.set_sregs(&sregs) .set_sregs(&sregs)
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
} }
@@ -1496,8 +1442,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_fpu(&self) -> cpu::Result<FpuState> { fn get_fpu(&self) -> cpu::Result<FpuState> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_fpu() .get_fpu()
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
.into()) .into())
@@ -1510,8 +1454,6 @@ impl cpu::Vcpu for KvmVcpu {
fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> { fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
let fpu: kvm_bindings::kvm_fpu = (*fpu).clone().into(); let fpu: kvm_bindings::kvm_fpu = (*fpu).clone().into();
self.fd self.fd
.lock()
.unwrap()
.set_fpu(&fpu) .set_fpu(&fpu)
.map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
} }
@@ -1527,8 +1469,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?; .map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
self.fd self.fd
.lock()
.unwrap()
.set_cpuid2(&kvm_cpuid) .set_cpuid2(&kvm_cpuid)
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
} }
@@ -1547,8 +1487,6 @@ impl cpu::Vcpu for KvmVcpu {
..Default::default() ..Default::default()
}; };
self.fd self.fd
.lock()
.unwrap()
.enable_cap(&cap) .enable_cap(&cap)
.map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into())) .map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into()))
} }
@@ -1560,8 +1498,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> { fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
let kvm_cpuid = self let kvm_cpuid = self
.fd .fd
.lock()
.unwrap()
.get_cpuid2(num_entries) .get_cpuid2(num_entries)
.map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into()))?;
@@ -1577,8 +1513,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_lapic(&self) -> cpu::Result<LapicState> { fn get_lapic(&self) -> cpu::Result<LapicState> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_lapic() .get_lapic()
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
.into()) .into())
@@ -1591,8 +1525,6 @@ impl cpu::Vcpu for KvmVcpu {
fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> { fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> {
let klapic: kvm_bindings::kvm_lapic_state = (*klapic).clone().into(); let klapic: kvm_bindings::kvm_lapic_state = (*klapic).clone().into();
self.fd self.fd
.lock()
.unwrap()
.set_lapic(&klapic) .set_lapic(&klapic)
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
} }
@@ -1606,8 +1538,6 @@ impl cpu::Vcpu for KvmVcpu {
let mut kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap(); let mut kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
let succ = self let succ = self
.fd .fd
.lock()
.unwrap()
.get_msrs(&mut kvm_msrs) .get_msrs(&mut kvm_msrs)
.map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?;
@@ -1630,8 +1560,6 @@ impl cpu::Vcpu for KvmVcpu {
let kvm_msrs: Vec<kvm_msr_entry> = msrs.iter().map(|e| (*e).into()).collect(); let kvm_msrs: Vec<kvm_msr_entry> = msrs.iter().map(|e| (*e).into()).collect();
let kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap(); let kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
self.fd self.fd
.lock()
.unwrap()
.set_msrs(&kvm_msrs) .set_msrs(&kvm_msrs)
.map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
} }
@@ -1642,8 +1570,6 @@ impl cpu::Vcpu for KvmVcpu {
fn get_mp_state(&self) -> cpu::Result<MpState> { fn get_mp_state(&self) -> cpu::Result<MpState> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_mp_state() .get_mp_state()
.map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))?
.into()) .into())
@@ -1654,8 +1580,6 @@ impl cpu::Vcpu for KvmVcpu {
/// ///
fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> { fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> {
self.fd self.fd
.lock()
.unwrap()
.set_mp_state(mp_state.into()) .set_mp_state(mp_state.into())
.map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
} }
@@ -1667,8 +1591,6 @@ impl cpu::Vcpu for KvmVcpu {
fn translate_gva(&self, gva: u64, _flags: u64) -> cpu::Result<(u64, u32)> { fn translate_gva(&self, gva: u64, _flags: u64) -> cpu::Result<(u64, u32)> {
let tr = self let tr = self
.fd .fd
.lock()
.unwrap()
.translate_gva(gva) .translate_gva(gva)
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
// tr.valid is set if the GVA is mapped to valid GPA. // tr.valid is set if the GVA is mapped to valid GPA.
@@ -1685,7 +1607,7 @@ impl cpu::Vcpu for KvmVcpu {
/// Triggers the running of the current virtual CPU returning an exit reason. /// Triggers the running of the current virtual CPU returning an exit reason.
/// ///
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> { fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
match self.fd.lock().unwrap().run() { match self.fd.run() {
Ok(run) => match run { Ok(run) => match run {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
VcpuExit::IoIn(addr, data) => { VcpuExit::IoIn(addr, data) => {
@@ -1696,7 +1618,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
} }
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::IoIn(addr, data))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
VcpuExit::IoOut(addr, data) => { VcpuExit::IoOut(addr, data) => {
@@ -1707,7 +1629,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
} }
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::IoOut(addr, data))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
VcpuExit::IoapicEoi(vector) => Ok(cpu::VmExit::IoapicEoi(vector)), VcpuExit::IoapicEoi(vector) => Ok(cpu::VmExit::IoapicEoi(vector)),
@@ -1740,7 +1662,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
} }
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::MmioRead(addr, data))
} }
VcpuExit::MmioWrite(addr, data) => { VcpuExit::MmioWrite(addr, data) => {
if let Some(vm_ops) = &self.vm_ops { if let Some(vm_ops) = &self.vm_ops {
@@ -1750,7 +1672,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
} }
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::MmioWrite(addr, data))
} }
VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv), VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv),
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
@@ -1779,7 +1701,7 @@ impl cpu::Vcpu for KvmVcpu {
/// potential soft lockups when being resumed. /// potential soft lockups when being resumed.
/// ///
fn notify_guest_clock_paused(&self) -> cpu::Result<()> { fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
if let Err(e) = self.fd.lock().unwrap().kvmclock_ctrl() { if let Err(e) = self.fd.kvmclock_ctrl() {
// Linux kernel returns -EINVAL if the PV clock isn't yet initialised // Linux kernel returns -EINVAL if the PV clock isn't yet initialised
// which could be because we're still in firmware or the guest doesn't // which could be because we're still in firmware or the guest doesn't
// use KVM clock. // use KVM clock.
@@ -1841,8 +1763,6 @@ impl cpu::Vcpu for KvmVcpu {
} }
} }
self.fd self.fd
.lock()
.unwrap()
.set_guest_debug(&dbg) .set_guest_debug(&dbg)
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
} }
@@ -1850,8 +1770,6 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> { fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
self.fd self.fd
.lock()
.unwrap()
.vcpu_init(kvi) .vcpu_init(kvi)
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into())) .map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
} }
@@ -1863,8 +1781,6 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> { fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
self.fd self.fd
.lock()
.unwrap()
.get_reg_list(reg_list) .get_reg_list(reg_list)
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))
} }
@@ -1897,8 +1813,6 @@ impl cpu::Vcpu for KvmVcpu {
| KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64); | KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64);
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(id, &mut bytes) .get_one_reg(id, &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
Ok(u64::from_le_bytes(bytes)) Ok(u64::from_le_bytes(bytes))
@@ -1926,8 +1840,6 @@ impl cpu::Vcpu for KvmVcpu {
// Get the register index of the PSTATE (Processor State) register. // Get the register index of the PSTATE (Processor State) register.
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off; let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate), arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
&PSTATE_FAULT_BITS_64.to_le_bytes(), &PSTATE_FAULT_BITS_64.to_le_bytes(),
@@ -1939,8 +1851,6 @@ impl cpu::Vcpu for KvmVcpu {
// Setting the PC (Processor Counter) to the current program address (kernel address). // Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset_of!(user_pt_regs, pc) + kreg_off; let pc = offset_of!(user_pt_regs, pc) + kreg_off;
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), arm64_core_reg_id!(KVM_REG_SIZE_U64, pc),
&boot_ip.to_le_bytes(), &boot_ip.to_le_bytes(),
@@ -1953,8 +1863,6 @@ impl cpu::Vcpu for KvmVcpu {
// We are choosing to place it the end of DRAM. See `get_fdt_addr`. // We are choosing to place it the end of DRAM. See `get_fdt_addr`.
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off; let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
self.fd self.fd
.lock()
.unwrap()
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
&fdt_start.to_le_bytes(), &fdt_start.to_le_bytes(),
@@ -2069,7 +1977,7 @@ impl cpu::Vcpu for KvmVcpu {
msr_entries msr_entries
}; };
let vcpu_events = self.get_vcpu_events()?; let vcpu_events = self.get_vcpu_events()?.into();
let tsc_khz = self.tsc_khz()?; let tsc_khz = self.tsc_khz()?;
Ok(VcpuKvmState { Ok(VcpuKvmState {
@@ -2106,8 +2014,6 @@ impl cpu::Vcpu for KvmVcpu {
let mut sys_regs: Vec<Register> = Vec::new(); let mut sys_regs: Vec<Register> = Vec::new();
let mut reg_list = RegList::new(500).unwrap(); let mut reg_list = RegList::new(500).unwrap();
self.fd self.fd
.lock()
.unwrap()
.get_reg_list(&mut reg_list) .get_reg_list(&mut reg_list)
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))?;
@@ -2126,8 +2032,6 @@ impl cpu::Vcpu for KvmVcpu {
for index in indices.iter() { for index in indices.iter() {
let mut bytes = [0_u8; 8]; let mut bytes = [0_u8; 8];
self.fd self.fd
.lock()
.unwrap()
.get_one_reg(*index, &mut bytes) .get_one_reg(*index, &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
sys_regs.push(kvm_bindings::kvm_one_reg { sys_regs.push(kvm_bindings::kvm_one_reg {
@@ -2226,7 +2130,7 @@ impl cpu::Vcpu for KvmVcpu {
} }
} }
self.set_vcpu_events(&state.vcpu_events)?; self.set_vcpu_events(&state.vcpu_events.into())?;
Ok(()) Ok(())
} }
@@ -2242,8 +2146,6 @@ impl cpu::Vcpu for KvmVcpu {
// Set system registers // Set system registers
for reg in &state.sys_regs { for reg in &state.sys_regs {
self.fd self.fd
.lock()
.unwrap()
.set_one_reg(reg.id, &reg.addr.to_le_bytes()) .set_one_reg(reg.id, &reg.addr.to_le_bytes())
.map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?;
} }
@@ -2258,20 +2160,15 @@ impl cpu::Vcpu for KvmVcpu {
/// ///
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
fn tdx_init(&self, hob_address: u64) -> cpu::Result<()> { fn tdx_init(&self, hob_address: u64) -> cpu::Result<()> {
tdx_command( tdx_command(&self.fd.as_raw_fd(), TdxCommand::InitVcpu, 0, hob_address)
&self.fd.lock().unwrap().as_raw_fd(), .map_err(cpu::HypervisorCpuError::InitializeTdx)
TdxCommand::InitVcpu,
0,
hob_address,
)
.map_err(cpu::HypervisorCpuError::InitializeTdx)
} }
/// ///
/// Set the "immediate_exit" state /// Set the "immediate_exit" state
/// ///
fn set_immediate_exit(&self, exit: bool) { fn set_immediate_exit(&self, exit: bool) {
self.fd.lock().unwrap().set_kvm_immediate_exit(exit.into()); self.fd.set_kvm_immediate_exit(exit.into());
} }
/// ///
@@ -2279,8 +2176,7 @@ impl cpu::Vcpu for KvmVcpu {
/// ///
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> { fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
let mut fd = self.fd.as_ref().lock().unwrap(); let kvm_run = self.fd.get_kvm_run();
let kvm_run = fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure // SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { let tdx_vmcall = unsafe {
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1 &mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
@@ -2309,8 +2205,7 @@ impl cpu::Vcpu for KvmVcpu {
/// ///
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
fn set_tdx_status(&mut self, status: TdxExitStatus) { fn set_tdx_status(&mut self, status: TdxExitStatus) {
let mut fd = self.fd.as_ref().lock().unwrap(); let kvm_run = self.fd.get_kvm_run();
let kvm_run = fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure // SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { let tdx_vmcall = unsafe {
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1 &mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
@@ -2359,7 +2254,7 @@ impl cpu::Vcpu for KvmVcpu {
addr: 0x0, addr: 0x0,
flags: 0, flags: 0,
}; };
self.fd.lock().unwrap().has_device_attr(&cpu_attr).is_ok() self.fd.has_device_attr(&cpu_attr).is_ok()
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@@ -2377,13 +2272,9 @@ impl cpu::Vcpu for KvmVcpu {
flags: 0, flags: 0,
}; };
self.fd self.fd
.lock()
.unwrap()
.set_device_attr(&cpu_attr_irq) .set_device_attr(&cpu_attr_irq)
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)?; .map_err(|_| cpu::HypervisorCpuError::InitializePmu)?;
self.fd self.fd
.lock()
.unwrap()
.set_device_attr(&cpu_attr) .set_device_attr(&cpu_attr)
.map_err(|_| cpu::HypervisorCpuError::InitializePmu) .map_err(|_| cpu::HypervisorCpuError::InitializePmu)
} }
@@ -2393,7 +2284,7 @@ impl cpu::Vcpu for KvmVcpu {
/// Get the frequency of the TSC if available /// Get the frequency of the TSC if available
/// ///
fn tsc_khz(&self) -> cpu::Result<Option<u32>> { fn tsc_khz(&self) -> cpu::Result<Option<u32>> {
match self.fd.lock().unwrap().get_tsc_khz() { match self.fd.get_tsc_khz() {
Err(e) => { Err(e) => {
if e.errno() == libc::EIO { if e.errno() == libc::EIO {
Ok(None) Ok(None)
@@ -2410,7 +2301,7 @@ impl cpu::Vcpu for KvmVcpu {
/// Set the frequency of the TSC if available /// Set the frequency of the TSC if available
/// ///
fn set_tsc_khz(&self, freq: u32) -> cpu::Result<()> { fn set_tsc_khz(&self, freq: u32) -> cpu::Result<()> {
match self.fd.lock().unwrap().set_tsc_khz(freq) { match self.fd.set_tsc_khz(freq) {
Err(e) => { Err(e) => {
if e.errno() == libc::EIO { if e.errno() == libc::EIO {
Ok(()) Ok(())
@@ -2421,23 +2312,6 @@ impl cpu::Vcpu for KvmVcpu {
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }
#[cfg(target_arch = "x86_64")]
///
/// Trigger NMI interrupt
///
fn nmi(&self) -> cpu::Result<()> {
match self.fd.lock().unwrap().nmi() {
Err(e) => {
if e.errno() == libc::EIO {
Ok(())
} else {
Err(cpu::HypervisorCpuError::Nmi(e.into()))
}
}
Ok(_) => Ok(()),
}
}
} }
impl KvmVcpu { impl KvmVcpu {
@@ -2448,8 +2322,6 @@ impl KvmVcpu {
fn get_xsave(&self) -> cpu::Result<XsaveState> { fn get_xsave(&self) -> cpu::Result<XsaveState> {
Ok(self Ok(self
.fd .fd
.lock()
.unwrap()
.get_xsave() .get_xsave()
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))?
.into()) .into())
@@ -2462,8 +2334,6 @@ impl KvmVcpu {
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> { fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into(); let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
self.fd self.fd
.lock()
.unwrap()
.set_xsave(&xsave) .set_xsave(&xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
} }
@@ -2474,8 +2344,6 @@ impl KvmVcpu {
/// ///
fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> { fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
self.fd self.fd
.lock()
.unwrap()
.get_xcrs() .get_xcrs()
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
} }
@@ -2486,8 +2354,6 @@ impl KvmVcpu {
/// ///
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> { fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
self.fd self.fd
.lock()
.unwrap()
.set_xcrs(xcrs) .set_xcrs(xcrs)
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
} }
@@ -2499,8 +2365,6 @@ impl KvmVcpu {
/// ///
fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> { fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
self.fd self.fd
.lock()
.unwrap()
.get_vcpu_events() .get_vcpu_events()
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
} }
@@ -2512,8 +2376,6 @@ impl KvmVcpu {
/// ///
fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> { fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
self.fd self.fd
.lock()
.unwrap()
.set_vcpu_events(events) .set_vcpu_events(events)
.map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
} }

View File

@@ -22,7 +22,7 @@ pub use {
kvm_bindings::kvm_cpuid_entry2, kvm_bindings::kvm_dtable, kvm_bindings::kvm_fpu, kvm_bindings::kvm_cpuid_entry2, kvm_bindings::kvm_dtable, kvm_bindings::kvm_fpu,
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState, kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment, kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events_old as VcpuEvents,
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave, kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave,
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries, kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX, kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX,

View File

@@ -20,7 +20,7 @@
#[macro_use] #[macro_use]
extern crate anyhow; extern crate anyhow;
#[allow(unused_imports)] #[cfg(target_arch = "x86_64")]
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@@ -134,7 +134,6 @@ pub const USER_MEMORY_REGION_READ: u32 = 1;
pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1; pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2; pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3; pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
#[derive(Debug)] #[derive(Debug)]
pub enum MpState { pub enum MpState {
@@ -163,7 +162,7 @@ pub enum CpuState {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub enum ClockData { pub enum ClockData {
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
Kvm(kvm_bindings::kvm_clock_data), Kvm(kvm_bindings::kvm_clock_data_old),
#[cfg(feature = "mshv")] #[cfg(feature = "mshv")]
Mshv, /* MSHV does not support ClockData yet */ Mshv, /* MSHV does not support ClockData yet */
} }

View File

@@ -13,8 +13,8 @@ use crate::hypervisor;
use crate::vec_with_array_field; use crate::vec_with_array_field;
use crate::vm::{self, InterruptSourceConfig, VmOps}; use crate::vm::{self, InterruptSourceConfig, VmOps};
use crate::HypervisorType; use crate::HypervisorType;
use mshv_bindings::*; pub use mshv_bindings::*;
use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType}; use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd, VmType};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@@ -29,13 +29,9 @@ pub mod x86_64;
#[cfg(feature = "sev_snp")] #[cfg(feature = "sev_snp")]
use snp_constants::*; use snp_constants::*;
#[cfg(target_arch = "x86_64")]
use crate::ClockData;
use crate::{ use crate::{
CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion, ClockData, CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_WRITE,
USER_MEMORY_REGION_WRITE,
}; };
#[cfg(feature = "sev_snp")] #[cfg(feature = "sev_snp")]
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK; use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
@@ -77,9 +73,6 @@ impl From<mshv_user_mem_region> for UserMemoryRegion {
if region.flags & HV_MAP_GPA_EXECUTABLE != 0 { if region.flags & HV_MAP_GPA_EXECUTABLE != 0 {
flags |= USER_MEMORY_REGION_EXECUTE; flags |= USER_MEMORY_REGION_EXECUTE;
} }
if region.flags & HV_MAP_GPA_ADJUSTABLE != 0 {
flags |= USER_MEMORY_REGION_ADJUSTABLE;
}
UserMemoryRegion { UserMemoryRegion {
guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64) guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64)
@@ -104,9 +97,6 @@ impl From<UserMemoryRegion> for mshv_user_mem_region {
if region.flags & USER_MEMORY_REGION_EXECUTE != 0 { if region.flags & USER_MEMORY_REGION_EXECUTE != 0 {
flags |= HV_MAP_GPA_EXECUTABLE; flags |= HV_MAP_GPA_EXECUTABLE;
} }
if region.flags & USER_MEMORY_REGION_ADJUSTABLE != 0 {
flags |= HV_MAP_GPA_ADJUSTABLE;
}
mshv_user_mem_region { mshv_user_mem_region {
guest_pfn: region.guest_phys_addr >> PAGE_SHIFT, guest_pfn: region.guest_phys_addr >> PAGE_SHIFT,
@@ -291,39 +281,25 @@ impl hypervisor::Hypervisor for MshvHypervisor {
) )
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?; .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
let msr_list = self.get_msr_list()?;
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
let mut msrs: Vec<MsrEntry> = vec![
MsrEntry {
..Default::default()
};
num_msrs
];
let indices = msr_list.as_slice();
for (pos, index) in indices.iter().enumerate() {
msrs[pos].index = *index;
}
let vm_fd = Arc::new(fd); let vm_fd = Arc::new(fd);
#[cfg(target_arch = "x86_64")] Ok(Arc::new(MshvVm {
{ fd: vm_fd,
let msr_list = self.get_msr_list()?; msrs,
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize; dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
let mut msrs: Vec<MsrEntry> = vec![ }))
MsrEntry {
..Default::default()
};
num_msrs
];
let indices = msr_list.as_slice();
for (pos, index) in indices.iter().enumerate() {
msrs[pos].index = *index;
}
Ok(Arc::new(MshvVm {
fd: vm_fd,
msrs,
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
#[cfg(feature = "sev_snp")]
sev_snp_enabled: mshv_vm_type == VmType::Snp,
}))
}
#[cfg(target_arch = "aarch64")]
{
Ok(Arc::new(MshvVm {
fd: vm_fd,
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
}))
}
} }
/// Create a mshv vm object and return the object as Vm trait object /// Create a mshv vm object and return the object as Vm trait object
@@ -341,7 +317,6 @@ impl hypervisor::Hypervisor for MshvHypervisor {
let vm_type = 0; let vm_type = 0;
self.create_vm_with_type(vm_type) self.create_vm_with_type(vm_type)
} }
#[cfg(target_arch = "x86_64")]
/// ///
/// Get the supported CpuID /// Get the supported CpuID
/// ///
@@ -361,11 +336,10 @@ impl hypervisor::Hypervisor for MshvHypervisor {
pub struct MshvVcpu { pub struct MshvVcpu {
fd: VcpuFd, fd: VcpuFd,
vp_index: u8, vp_index: u8,
#[cfg(target_arch = "x86_64")]
cpuid: Vec<CpuIdEntry>, cpuid: Vec<CpuIdEntry>,
#[cfg(target_arch = "x86_64")]
msrs: Vec<MsrEntry>, msrs: Vec<MsrEntry>,
vm_ops: Option<Arc<dyn vm::VmOps>>, vm_ops: Option<Arc<dyn vm::VmOps>>,
#[cfg(feature = "sev_snp")]
vm_fd: Arc<VmFd>, vm_fd: Arc<VmFd>,
} }
@@ -508,7 +482,6 @@ impl cpu::Vcpu for MshvVcpu {
warn!("TRIPLE FAULT"); warn!("TRIPLE FAULT");
Ok(cpu::VmExit::Shutdown) Ok(cpu::VmExit::Shutdown)
} }
#[cfg(target_arch = "x86_64")]
hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => { hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => {
let info = x.to_ioport_info().unwrap(); let info = x.to_ioport_info().unwrap();
let access_info = info.access_info; let access_info = info.access_info;
@@ -599,7 +572,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::Ignore)
} }
#[cfg(target_arch = "x86_64")]
hv_message_type_HVMSG_UNMAPPED_GPA => { hv_message_type_HVMSG_UNMAPPED_GPA => {
let info = x.to_memory_info().unwrap(); let info = x.to_memory_info().unwrap();
let insn_len = info.instruction_byte_count as usize; let insn_len = info.instruction_byte_count as usize;
@@ -625,70 +597,6 @@ impl cpu::Vcpu for MshvVcpu {
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::Ignore)
} }
#[cfg(feature = "sev_snp")]
hv_message_type_HVMSG_GPA_ATTRIBUTE_INTERCEPT => {
let info = x.to_gpa_attribute_info().unwrap();
let host_vis = info.__bindgen_anon_1.host_visibility();
if host_vis >= HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE {
warn!("Ignored attribute intercept with full host visibility");
return Ok(cpu::VmExit::Ignore);
}
let num_ranges = info.__bindgen_anon_1.range_count();
assert!(num_ranges >= 1);
if num_ranges > 1 {
return Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unhandled VCPU exit(GPA_ATTRIBUTE_INTERCEPT): Expected num_ranges to be 1 but found num_ranges {:?}",
num_ranges
)));
}
// TODO: we could also deny the request with HvCallCompleteIntercept
let mut gpas = Vec::new();
let ranges = info.ranges;
let (gfn_start, gfn_count) = snp::parse_gpa_range(ranges[0]).unwrap();
debug!(
"Releasing pages: gfn_start: {:x?}, gfn_count: {:?}",
gfn_start, gfn_count
);
let gpa_start = gfn_start * HV_PAGE_SIZE as u64;
for i in 0..gfn_count {
gpas.push(gpa_start + i * HV_PAGE_SIZE as u64);
}
let mut gpa_list =
vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len());
gpa_list[0].gpa_list_size = gpas.len() as u64;
gpa_list[0].host_access = host_vis;
gpa_list[0].acquire = 0;
gpa_list[0].flags = 0;
// SAFETY: gpa_list initialized with gpas.len() and now it is being turned into
// gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold
// everything from gpas.
unsafe {
let gpas_slice: &mut [u64] = gpa_list[0].gpa_list.as_mut_slice(gpas.len());
gpas_slice.copy_from_slice(gpas.as_slice());
}
self.vm_fd
.modify_gpa_host_access(&gpa_list[0])
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unhandled VCPU exit: attribute intercept - couldn't modify host access {}", e
)))?;
Ok(cpu::VmExit::Ignore)
}
hv_message_type_HVMSG_UNACCEPTED_GPA => {
let info = x.to_memory_info().unwrap();
let gva = info.guest_virtual_address;
let gpa = info.guest_physical_address;
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unhandled VCPU exit: Unaccepted GPA({:x}) found at GVA({:x})",
gpa,
gva,
)))
}
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => { hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
let info = x.to_cpuid_info().unwrap(); let info = x.to_cpuid_info().unwrap();
debug!("cpuid eax: {:x}", { info.rax }); debug!("cpuid eax: {:x}", { info.rax });
@@ -709,7 +617,6 @@ impl cpu::Vcpu for MshvVcpu {
debug!("Exception Info {:?}", { info.exception_vector }); debug!("Exception Info {:?}", { info.exception_vector });
Ok(cpu::VmExit::Ignore) Ok(cpu::VmExit::Ignore)
} }
#[cfg(target_arch = "x86_64")]
hv_message_type_HVMSG_X64_APIC_EOI => { hv_message_type_HVMSG_X64_APIC_EOI => {
let info = x.to_apic_eoi_info().unwrap(); let info = x.to_apic_eoi_info().unwrap();
// The kernel should dispatch the EOI to the correct thread. // The kernel should dispatch the EOI to the correct thread.
@@ -1123,14 +1030,13 @@ impl cpu::Vcpu for MshvVcpu {
.sev_snp_ap_create(&mshv_ap_create_req) .sev_snp_ap_create(&mshv_ap_create_req)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
let mut swei1_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa { let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET, base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32, byte_count: std::mem::size_of::<u64>() as u32,
..Default::default() ..Default::default()
}; };
self.fd self.fd
.gpa_write(&mut swei1_rw_gpa_arg) .gpa_write(&mut swei2_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
} }
_ => panic!( _ => panic!(
@@ -1160,46 +1066,6 @@ impl cpu::Vcpu for MshvVcpu {
} }
} }
#[cfg(target_arch = "aarch64")]
fn init_pmu(&self, irq: u32) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn has_pmu_support(&self) -> bool {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn get_sys_reg(&self, sys_reg: u32) -> cpu::Result<u64> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
unimplemented!()
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call to setup the CPUID registers. /// X86 specific call to setup the CPUID registers.
@@ -1275,18 +1141,19 @@ impl cpu::Vcpu for MshvVcpu {
Ok(()) Ok(())
} }
#[cfg(target_arch = "x86_64")]
/// ///
/// Set CPU state for x86_64 guest. /// Set CPU state
/// ///
fn set_state(&self, state: &CpuState) -> cpu::Result<()> { fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
let mut state: VcpuMshvState = state.clone().into(); let state: VcpuMshvState = state.clone().into();
self.set_msrs(&state.msrs)?; self.set_msrs(&state.msrs)?;
self.set_vcpu_events(&state.vcpu_events)?; self.set_vcpu_events(&state.vcpu_events)?;
self.set_regs(&state.regs.into())?; self.set_regs(&state.regs.into())?;
self.set_sregs(&state.sregs.into())?; self.set_sregs(&state.sregs.into())?;
self.set_fpu(&state.fpu)?; self.set_fpu(&state.fpu)?;
self.set_xcrs(&state.xcrs)?; self.set_xcrs(&state.xcrs)?;
self.set_lapic(&state.lapic)?;
self.set_xsave(&state.xsave)?;
// These registers are global and needed to be set only for first VCPU // These registers are global and needed to be set only for first VCPU
// as Microsoft Hypervisor allows setting this regsier for only one VCPU // as Microsoft Hypervisor allows setting this regsier for only one VCPU
if self.vp_index == 0 { if self.vp_index == 0 {
@@ -1297,23 +1164,11 @@ impl cpu::Vcpu for MshvVcpu {
self.fd self.fd
.set_debug_regs(&state.dbg) .set_debug_regs(&state.dbg)
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
self.fd
.set_all_vp_state_components(&mut state.vp_states)
.map_err(|e| cpu::HypervisorCpuError::SetAllVpStateComponents(e.into()))?;
Ok(()) Ok(())
} }
#[cfg(target_arch = "aarch64")]
/// ///
/// Set CPU state for aarch64 guest. /// Get CPU State
///
fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
unimplemented!()
}
#[cfg(target_arch = "x86_64")]
///
/// Get CPU State for x86_64 guest
/// ///
fn state(&self) -> cpu::Result<CpuState> { fn state(&self) -> cpu::Result<CpuState> {
let regs = self.get_regs()?; let regs = self.get_regs()?;
@@ -1323,6 +1178,8 @@ impl cpu::Vcpu for MshvVcpu {
let vcpu_events = self.get_vcpu_events()?; let vcpu_events = self.get_vcpu_events()?;
let mut msrs = self.msrs.clone(); let mut msrs = self.msrs.clone();
self.get_msrs(&mut msrs)?; self.get_msrs(&mut msrs)?;
let lapic = self.get_lapic()?;
let xsave = self.get_xsave()?;
let misc = self let misc = self
.fd .fd
.get_misc_regs() .get_misc_regs()
@@ -1331,10 +1188,6 @@ impl cpu::Vcpu for MshvVcpu {
.fd .fd
.get_debug_regs() .get_debug_regs()
.map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?;
let vp_states = self
.fd
.get_all_vp_state_components()
.map_err(|e| cpu::HypervisorCpuError::GetAllVpStateComponents(e.into()))?;
Ok(VcpuMshvState { Ok(VcpuMshvState {
msrs, msrs,
@@ -1343,21 +1196,14 @@ impl cpu::Vcpu for MshvVcpu {
sregs: sregs.into(), sregs: sregs.into(),
fpu, fpu,
xcrs, xcrs,
lapic,
dbg, dbg,
xsave,
misc, misc,
vp_states,
} }
.into()) .into())
} }
#[cfg(target_arch = "aarch64")]
///
/// Get CPU state for aarch64 guest.
///
fn state(&self) -> cpu::Result<CpuState> {
unimplemented!()
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Translate guest virtual address to guest physical address /// Translate guest virtual address to guest physical address
@@ -1395,38 +1241,29 @@ impl cpu::Vcpu for MshvVcpu {
] ]
.to_vec() .to_vec()
} }
///
/// Sets the AMD specific vcpu's sev control register.
///
#[cfg(feature = "sev_snp")]
fn set_sev_control_register(&self, vmsa_pfn: u64) -> cpu::Result<()> {
let sev_control_reg = snp::get_sev_control_register(vmsa_pfn);
self.fd
.set_sev_control_register(sev_control_reg)
.map_err(|e| cpu::HypervisorCpuError::SetSevControlRegister(e.into()))
}
#[cfg(target_arch = "x86_64")]
///
/// Trigger NMI interrupt
///
fn nmi(&self) -> cpu::Result<()> {
let cfg = InterruptRequest {
interrupt_type: hv_interrupt_type_HV_X64_INTERRUPT_TYPE_NMI,
apic_id: self.vp_index as u64,
level_triggered: false,
vector: 0,
logical_destination_mode: false,
long_mode: false,
};
self.vm_fd
.request_virtual_interrupt(&cfg)
.map_err(|e| cpu::HypervisorCpuError::Nmi(e.into()))
}
} }
impl MshvVcpu { impl MshvVcpu {
#[cfg(target_arch = "x86_64")]
///
/// X86 specific call that returns the vcpu's current "xsave struct".
///
fn get_xsave(&self) -> cpu::Result<Xsave> {
self.fd
.get_xsave()
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
}
#[cfg(target_arch = "x86_64")]
///
/// X86 specific call that sets the vcpu's current "xsave struct".
///
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
self.fd
.set_xsave(xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that returns the vcpu's current "xcrs". /// X86 specific call that returns the vcpu's current "xcrs".
@@ -1470,13 +1307,11 @@ impl MshvVcpu {
} }
} }
#[cfg(target_arch = "x86_64")]
struct MshvEmulatorContext<'a> { struct MshvEmulatorContext<'a> {
vcpu: &'a MshvVcpu, vcpu: &'a MshvVcpu,
map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor
} }
#[cfg(target_arch = "x86_64")]
impl<'a> MshvEmulatorContext<'a> { impl<'a> MshvEmulatorContext<'a> {
// Do the actual gva -> gpa translation // Do the actual gva -> gpa translation
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
@@ -1500,7 +1335,6 @@ impl<'a> MshvEmulatorContext<'a> {
} }
} }
#[cfg(target_arch = "x86_64")]
/// Platform emulation for Hyper-V /// Platform emulation for Hyper-V
impl<'a> PlatformEmulator for MshvEmulatorContext<'a> { impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
type CpuState = EmulatorCpuState; type CpuState = EmulatorCpuState;
@@ -1601,11 +1435,8 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
/// Wrapper over Mshv VM ioctls. /// Wrapper over Mshv VM ioctls.
pub struct MshvVm { pub struct MshvVm {
fd: Arc<VmFd>, fd: Arc<VmFd>,
#[cfg(target_arch = "x86_64")]
msrs: Vec<MsrEntry>, msrs: Vec<MsrEntry>,
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>, dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
#[cfg(feature = "sev_snp")]
sev_snp_enabled: bool,
} }
impl MshvVm { impl MshvVm {
@@ -1700,11 +1531,10 @@ impl vm::Vm for MshvVm {
let vcpu = MshvVcpu { let vcpu = MshvVcpu {
fd: vcpu_fd, fd: vcpu_fd,
vp_index: id, vp_index: id,
#[cfg(target_arch = "x86_64")]
cpuid: Vec::new(), cpuid: Vec::new(),
#[cfg(target_arch = "x86_64")]
msrs: self.msrs.clone(), msrs: self.msrs.clone(),
vm_ops, vm_ops,
#[cfg(feature = "sev_snp")]
vm_fd: self.fd.clone(), vm_fd: self.fd.clone(),
}; };
Ok(Arc::new(vcpu)) Ok(Arc::new(vcpu))
@@ -1726,11 +1556,6 @@ impl vm::Vm for MshvVm {
addr: &IoEventAddress, addr: &IoEventAddress,
datamatch: Option<DataMatch>, datamatch: Option<DataMatch>,
) -> vm::Result<()> { ) -> vm::Result<()> {
#[cfg(feature = "sev_snp")]
if self.sev_snp_enabled {
return Ok(());
}
let addr = &mshv_ioctls::IoEventAddress::from(*addr); let addr = &mshv_ioctls::IoEventAddress::from(*addr);
debug!( debug!(
"register_ioevent fd {} addr {:x?} datamatch {:?}", "register_ioevent fd {} addr {:x?} datamatch {:?}",
@@ -1758,11 +1583,6 @@ impl vm::Vm for MshvVm {
/// Unregister an event from a certain address it has been previously registered to. /// Unregister an event from a certain address it has been previously registered to.
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> { fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
#[cfg(feature = "sev_snp")]
if self.sev_snp_enabled {
return Ok(());
}
let addr = &mshv_ioctls::IoEventAddress::from(*addr); let addr = &mshv_ioctls::IoEventAddress::from(*addr);
debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr); debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr);
@@ -1815,7 +1635,7 @@ impl vm::Vm for MshvVm {
readonly: bool, readonly: bool,
_log_dirty_pages: bool, _log_dirty_pages: bool,
) -> UserMemoryRegion { ) -> UserMemoryRegion {
let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_ADJUSTABLE; let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE;
if !readonly { if !readonly {
flags |= HV_MAP_GPA_WRITABLE; flags |= HV_MAP_GPA_WRITABLE;
} }
@@ -1994,7 +1814,7 @@ impl vm::Vm for MshvVm {
fn complete_isolated_import( fn complete_isolated_import(
&self, &self,
snp_id_block: IGVM_VHS_SNP_ID_BLOCK, snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
host_data: [u8; 32], host_data: &[u8],
id_block_enabled: u8, id_block_enabled: u8,
) -> vm::Result<()> { ) -> vm::Result<()> {
let mut auth_info = hv_snp_id_auth_info { let mut auth_info = hv_snp_id_auth_info {
@@ -2027,7 +1847,7 @@ impl vm::Vm for MshvVm {
policy: get_default_snp_guest_policy(), policy: get_default_snp_guest_policy(),
}, },
id_auth_info: auth_info, id_auth_info: auth_info,
host_data, host_data: host_data[0..32].try_into().unwrap(),
id_block_enabled, id_block_enabled,
author_key_enabled: 0, author_key_enabled: 0,
}, },
@@ -2037,14 +1857,4 @@ impl vm::Vm for MshvVm {
.complete_isolated_import(&data) .complete_isolated_import(&data)
.map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into())) .map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into()))
} }
#[cfg(target_arch = "aarch64")]
fn create_vgic(&self, config: VgicConfig) -> vm::Result<Arc<Mutex<dyn Vgic>>> {
unimplemented!()
}
#[cfg(target_arch = "aarch64")]
fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> {
unimplemented!()
}
} }

View File

@@ -19,10 +19,10 @@ use std::fmt;
/// ///
pub use { pub use {
mshv_bindings::hv_cpuid_entry, mshv_bindings::mshv_user_mem_region as MemoryRegion, mshv_bindings::hv_cpuid_entry, mshv_bindings::mshv_user_mem_region as MemoryRegion,
mshv_bindings::msr_entry, mshv_bindings::AllVpStateComponents, mshv_bindings::CpuId, mshv_bindings::msr_entry, mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
mshv_bindings::DebugRegisters, mshv_bindings::FloatingPointUnit, mshv_bindings::FloatingPointUnit, mshv_bindings::LapicState as MshvLapicState,
mshv_bindings::LapicState as MshvLapicState, mshv_bindings::MiscRegs as MiscRegisters, mshv_bindings::MiscRegs as MiscRegisters, mshv_bindings::MsrList,
mshv_bindings::MsrList, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
mshv_bindings::SegmentRegister as MshvSegmentRegister, mshv_bindings::SegmentRegister as MshvSegmentRegister,
mshv_bindings::SpecialRegisters as MshvSpecialRegisters, mshv_bindings::SpecialRegisters as MshvSpecialRegisters,
mshv_bindings::StandardRegisters as MshvStandardRegisters, mshv_bindings::SuspendRegisters, mshv_bindings::StandardRegisters as MshvStandardRegisters, mshv_bindings::SuspendRegisters,
@@ -38,9 +38,10 @@ pub struct VcpuMshvState {
pub sregs: MshvSpecialRegisters, pub sregs: MshvSpecialRegisters,
pub fpu: FpuState, pub fpu: FpuState,
pub xcrs: ExtendedControlRegisters, pub xcrs: ExtendedControlRegisters,
pub lapic: LapicState,
pub dbg: DebugRegisters, pub dbg: DebugRegisters,
pub xsave: Xsave,
pub misc: MiscRegisters, pub misc: MiscRegisters,
pub vp_states: AllVpStateComponents,
} }
impl fmt::Display for VcpuMshvState { impl fmt::Display for VcpuMshvState {
@@ -52,7 +53,7 @@ impl fmt::Display for VcpuMshvState {
msr_entries[i][1] = entry.data; msr_entries[i][1] = entry.data;
msr_entries[i][0] = entry.index as u64; msr_entries[i][0] = entry.index as u64;
} }
write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- DBG: {:?} --- VP States: {:?}", write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- Local APIC: {:?} --- DBG: {:?} --- Xsave: {:?}",
msr_entries.len(), msr_entries.len(),
msr_entries, msr_entries,
self.vcpu_events, self.vcpu_events,
@@ -60,8 +61,9 @@ impl fmt::Display for VcpuMshvState {
self.sregs, self.sregs,
self.fpu, self.fpu,
self.xcrs, self.xcrs,
self.lapic,
self.dbg, self.dbg,
self.vp_states, self.xsave,
) )
} }
} }

View File

@@ -385,7 +385,7 @@ pub trait Vm: Send + Sync + Any {
fn complete_isolated_import( fn complete_isolated_import(
&self, &self,
_snp_id_block: IGVM_VHS_SNP_ID_BLOCK, _snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
_host_data: [u8; 32], _host_data: &[u8],
_id_block_enabled: u8, _id_block_enabled: u8,
) -> Result<()> { ) -> Result<()> {
unimplemented!() unimplemented!()

View File

@@ -1,8 +1,6 @@
// Copyright TUNTAP, 2017 The Chromium OS Authors. All rights reserved. // Copyright TUNTAP, 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file. // found in the THIRD-PARTY file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]

View File

@@ -6,21 +6,23 @@ edition = "2021"
[dependencies] [dependencies]
epoll = "4.3.3" epoll = "4.3.3"
getrandom = "0.2.13" getrandom = "0.2.10"
libc = "0.2.153" libc = "0.2.147"
log = "0.4.21" log = "0.4.20"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
serde = "1.0.197" serde = "1.0.168"
thiserror = "1.0.58" thiserror = "1.0.52"
virtio-bindings = "0.2.2" versionize = "0.2.0"
versionize_derive = "0.1.6"
virtio-bindings = "0.2.0"
virtio-queue = "0.11.0" virtio-queue = "0.11.0"
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"
[dev-dependencies] [dev-dependencies]
once_cell = "1.19.0" once_cell = "1.18.0"
pnet = "0.34.0" pnet = "0.34.0"
pnet_datalink = "0.34.0" pnet_datalink = "0.34.0"
serde_json = "1.0.115" serde_json = "1.0.107"

View File

@@ -14,13 +14,13 @@ mod open_tap;
mod queue_pair; mod queue_pair;
mod tap; mod tap;
use serde::{Deserialize, Serialize};
use std::io::Error as IoError; use std::io::Error as IoError;
use std::os::raw::c_uint; use std::os::raw::c_uint;
use std::os::unix::io::{FromRawFd, RawFd}; use std::os::unix::io::{FromRawFd, RawFd};
use std::{io, mem, net}; use std::{io, mem, net};
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use virtio_bindings::virtio_net::{ use virtio_bindings::virtio_net::{
virtio_net_hdr_v1, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN, virtio_net_hdr_v1, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4,
@@ -45,7 +45,7 @@ pub enum Error {
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
#[repr(C, packed)] #[repr(C, packed)]
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Versionize)]
pub struct VirtioNetConfig { pub struct VirtioNetConfig {
pub mac: [u8; 6], pub mac: [u8; 6],
pub status: u16, pub status: u16,

View File

@@ -7,6 +7,7 @@
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::result::Result;
use std::str::FromStr; use std::str::FromStr;
use serde::de::{Deserialize, Deserializer, Error}; use serde::de::{Deserialize, Deserializer, Error};

View File

@@ -290,17 +290,6 @@ impl TupleValue for Vec<u64> {
} }
} }
impl TupleValue for Vec<usize> {
fn parse_value(input: &str) -> Result<Self, TupleError> {
Ok(IntegerList::from_str(input)
.map_err(TupleError::InvalidIntegerList)?
.0
.iter()
.map(|v| *v as usize)
.collect())
}
}
pub struct Tuple<S, T>(pub Vec<(S, T)>); pub struct Tuple<S, T>(pub Vec<(S, T)>);
pub enum TupleError { pub enum TupleError {

View File

@@ -10,19 +10,21 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.81" anyhow = "1.0.75"
byteorder = "1.5.0" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] } vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-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" } vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"
libc = "0.2.153" libc = "0.2.147"
log = "0.4.21" log = "0.4.20"
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.168", features = ["derive"] }
thiserror = "1.0.58" thiserror = "1.0.52"
versionize = "0.2.0"
versionize_derive = "0.1.6"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::configuration::{ use crate::configuration::{
PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType, PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,

View File

@@ -1,17 +1,16 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::device::BarReprogrammingParams; use crate::device::BarReprogrammingParams;
use crate::{MsixConfig, PciInterruptPin}; use crate::{MsixConfig, PciInterruptPin};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::PciBarType; use vm_device::PciBarType;
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
// The number of 32bit registers in the config space, 4096 bytes. // The number of 32bit registers in the config space, 4096 bytes.
const NUM_CONFIGURATION_REGISTERS: usize = 1024; const NUM_CONFIGURATION_REGISTERS: usize = 1024;
@@ -397,7 +396,7 @@ fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
None None
} }
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Copy, Versionize)]
struct PciBar { struct PciBar {
addr: u32, addr: u32,
size: u32, size: u32,
@@ -405,7 +404,7 @@ struct PciBar {
r#type: Option<PciBarRegionType>, r#type: Option<PciBarRegionType>,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct PciConfigurationState { pub struct PciConfigurationState {
registers: Vec<u32>, registers: Vec<u32>,
writable_bits: Vec<u32>, writable_bits: Vec<u32>,
@@ -417,6 +416,8 @@ pub struct PciConfigurationState {
msix_cap_reg_idx: Option<usize>, msix_cap_reg_idx: Option<usize>,
} }
impl VersionMapped for PciConfigurationState {}
/// Contains the configuration space of a PCI node. /// Contains the configuration space of a PCI node.
/// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
/// The configuration space is accessed with DWORD reads and writes from the guest. /// The configuration space is accessed with DWORD reads and writes from the guest.
@@ -434,7 +435,7 @@ pub struct PciConfiguration {
} }
/// See pci_regs.h in kernel /// See pci_regs.h in kernel
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)]
pub enum PciBarRegionType { pub enum PciBarRegionType {
Memory32BitRegion = 0, Memory32BitRegion = 0,
IoRegion = 0x01, IoRegion = 0x01,
@@ -1069,7 +1070,7 @@ impl Snapshottable for PciConfiguration {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }

View File

@@ -1,15 +1,13 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::configuration::{self, PciBarRegionType}; use crate::configuration::{self, PciBarRegionType};
use crate::PciBarConfiguration; use crate::PciBarConfiguration;
use std::any::Any; use std::any::Any;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use std::{io, result}; use std::{self, io, result};
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::{BusDevice, Resource}; use vm_device::{BusDevice, Resource};

View File

@@ -1,8 +1,6 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved. // Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
//! Implements pci devices and busses. //! Implements pci devices and busses.
#[macro_use] #[macro_use]
@@ -28,7 +26,7 @@ pub use self::device::{
}; };
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig}; pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE}; pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE};
pub use self::vfio::{MmioRegion, VfioDmaMapping, VfioPciDevice, VfioPciError}; pub use self::vfio::{VfioPciDevice, VfioPciError};
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError}; pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
use serde::de::Visitor; use serde::de::Visitor;
use std::fmt::{self, Display}; use std::fmt::{self, Display};

View File

@@ -4,14 +4,15 @@
// //
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
use std::io; use std::io;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig, InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
}; };
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
// MSI control masks // MSI control masks
const MSI_CTL_ENABLE: u16 = 0x1; const MSI_CTL_ENABLE: u16 = 0x1;
@@ -46,7 +47,7 @@ pub enum Error {
pub const MSI_CONFIG_ID: &str = "msi_config"; pub const MSI_CONFIG_ID: &str = "msi_config";
#[derive(Clone, Copy, Default, Serialize, Deserialize)] #[derive(Clone, Copy, Default, Versionize)]
pub struct MsiCap { pub struct MsiCap {
// Message Control Register // Message Control Register
// 0: MSI enable. // 0: MSI enable.
@@ -171,11 +172,13 @@ impl MsiCap {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct MsiConfigState { pub struct MsiConfigState {
cap: MsiCap, cap: MsiCap,
} }
impl VersionMapped for MsiConfigState {}
pub struct MsiConfig { pub struct MsiConfig {
pub cap: MsiCap, pub cap: MsiCap,
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
@@ -291,6 +294,6 @@ impl Snapshottable for MsiConfig {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }

View File

@@ -5,16 +5,16 @@
use crate::{PciCapability, PciCapabilityId}; use crate::{PciCapability, PciCapabilityId};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use serde::Deserialize;
use serde::Serialize;
use std::io; use std::io;
use std::result; use std::result;
use std::sync::Arc; use std::sync::Arc;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig, InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
}; };
use vm_memory::ByteValued; use vm_memory::ByteValued;
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048; const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
const MSIX_TABLE_ENTRIES_MODULO: u64 = 16; const MSIX_TABLE_ENTRIES_MODULO: u64 = 16;
@@ -35,7 +35,7 @@ pub enum Error {
UpdateInterruptRoute(io::Error), UpdateInterruptRoute(io::Error),
} }
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Clone, Versionize, Eq, PartialEq)]
pub struct MsixTableEntry { pub struct MsixTableEntry {
pub msg_addr_lo: u32, pub msg_addr_lo: u32,
pub msg_addr_hi: u32, pub msg_addr_hi: u32,
@@ -60,7 +60,7 @@ impl Default for MsixTableEntry {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
pub struct MsixConfigState { pub struct MsixConfigState {
table_entries: Vec<MsixTableEntry>, table_entries: Vec<MsixTableEntry>,
pba_entries: Vec<u64>, pba_entries: Vec<u64>,
@@ -68,6 +68,8 @@ pub struct MsixConfigState {
enabled: bool, enabled: bool,
} }
impl VersionMapped for MsixConfigState {}
pub struct MsixConfig { pub struct MsixConfig {
pub table_entries: Vec<MsixTableEntry>, pub table_entries: Vec<MsixTableEntry>,
pub pba_entries: Vec<u64>, pub pba_entries: Vec<u64>,
@@ -434,13 +436,13 @@ impl Snapshottable for MsixConfig {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_state(&self.state()) Snapshot::new_from_versioned_state(&self.state())
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[repr(packed)] #[repr(packed)]
#[derive(Clone, Copy, Default, Serialize, Deserialize)] #[derive(Clone, Copy, Default, Versionize)]
pub struct MsixCap { pub struct MsixCap {
// Message Control Register // Message Control Register
// 10-0: MSI-X Table size // 10-0: MSI-X Table size

View File

@@ -15,7 +15,6 @@ use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError; use hypervisor::HypervisorVmError;
use libc::{sysconf, _SC_PAGESIZE}; use libc::{sysconf, _SC_PAGESIZE};
use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::io; use std::io;
@@ -23,6 +22,8 @@ use std::os::unix::io::AsRawFd;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vfio_bindings::bindings::vfio::*; use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::{ use vfio_ioctls::{
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea, VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
@@ -31,13 +32,14 @@ use vm_allocator::page_size::{
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned, 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, SystemAllocator};
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig, InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
}; };
use vm_device::{BusDevice, Resource}; use vm_device::{BusDevice, Resource};
use vm_memory::{Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestUsize}; use vm_memory::{Address, GuestAddress, GuestUsize};
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub(crate) const VFIO_COMMON_ID: &str = "vfio_common"; pub(crate) const VFIO_COMMON_ID: &str = "vfio_common";
@@ -92,7 +94,7 @@ enum InterruptUpdateAction {
DisableMsix, DisableMsix,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
struct IntxState { struct IntxState {
enabled: bool, enabled: bool,
} }
@@ -102,7 +104,7 @@ pub(crate) struct VfioIntx {
enabled: bool, enabled: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
struct MsiState { struct MsiState {
cap: MsiCap, cap: MsiCap,
cap_offset: u32, cap_offset: u32,
@@ -134,7 +136,7 @@ impl VfioMsi {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
struct MsixState { struct MsixState {
cap: MsixCap, cap: MsixCap,
cap_offset: u32, cap_offset: u32,
@@ -272,48 +274,6 @@ pub struct MmioRegion {
pub(crate) index: u32, pub(crate) index: u32,
pub(crate) user_memory_regions: Vec<UserMemoryRegion>, pub(crate) user_memory_regions: Vec<UserMemoryRegion>,
} }
trait MmioRegionRange {
fn check_range(&self, guest_addr: u64, size: u64) -> bool;
fn find_user_address(&self, guest_addr: u64) -> Result<u64, io::Error>;
}
impl MmioRegionRange for Vec<MmioRegion> {
// Check if a guest address is within the range of mmio regions
fn check_range(&self, guest_addr: u64, size: u64) -> bool {
for region in self.iter() {
let Some(guest_addr_end) = guest_addr.checked_add(size) else {
return false;
};
let Some(region_end) = region.start.raw_value().checked_add(region.length) else {
return false;
};
if guest_addr >= region.start.raw_value() && guest_addr_end <= region_end {
return true;
}
}
false
}
// Locate the user region address for a guest address within all mmio regions
fn find_user_address(&self, guest_addr: u64) -> Result<u64, io::Error> {
for region in self.iter() {
for user_region in region.user_memory_regions.iter() {
if guest_addr >= user_region.start
&& guest_addr < user_region.start + user_region.size
{
return Ok(user_region.host_addr + (guest_addr - user_region.start));
}
}
}
Err(io::Error::new(
io::ErrorKind::Other,
format!("unable to find user address: 0x{guest_addr:x}"),
))
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum VfioError { pub enum VfioError {
#[error("Kernel VFIO error: {0}")] #[error("Kernel VFIO error: {0}")]
@@ -437,13 +397,15 @@ impl Vfio for VfioDeviceWrapper {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Versionize)]
struct VfioCommonState { struct VfioCommonState {
intx_state: Option<IntxState>, intx_state: Option<IntxState>,
msi_state: Option<MsiState>, msi_state: Option<MsiState>,
msix_state: Option<MsixState>, msix_state: Option<MsixState>,
} }
impl VersionMapped for VfioCommonState {}
pub(crate) struct ConfigPatch { pub(crate) struct ConfigPatch {
mask: u32, mask: u32,
patch: u32, patch: u32,
@@ -457,7 +419,6 @@ pub(crate) struct VfioCommon {
pub(crate) legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>, pub(crate) legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
pub(crate) vfio_wrapper: Arc<dyn Vfio>, pub(crate) vfio_wrapper: Arc<dyn Vfio>,
pub(crate) patches: HashMap<usize, ConfigPatch>, pub(crate) patches: HashMap<usize, ConfigPatch>,
x_nv_gpudirect_clique: Option<u8>,
} }
impl VfioCommon { impl VfioCommon {
@@ -468,15 +429,15 @@ impl VfioCommon {
subclass: &dyn PciSubclass, subclass: &dyn PciSubclass,
bdf: PciBdf, bdf: PciBdf,
snapshot: Option<Snapshot>, snapshot: Option<Snapshot>,
x_nv_gpudirect_clique: Option<u8>,
) -> Result<Self, VfioPciError> { ) -> Result<Self, VfioPciError> {
let pci_configuration_state = let pci_configuration_state =
vm_migration::state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID).map_err(|e| { vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
VfioPciError::RetrievePciConfigurationState(anyhow!( .map_err(|e| {
"Failed to get PciConfigurationState from Snapshot: {}", VfioPciError::RetrievePciConfigurationState(anyhow!(
e "Failed to get PciConfigurationState from Snapshot: {}",
)) e
})?; ))
})?;
let configuration = PciConfiguration::new( let configuration = PciConfiguration::new(
0, 0,
@@ -504,12 +465,11 @@ impl VfioCommon {
legacy_interrupt_group, legacy_interrupt_group,
vfio_wrapper, vfio_wrapper,
patches: HashMap::new(), patches: HashMap::new(),
x_nv_gpudirect_clique,
}; };
let state: Option<VfioCommonState> = snapshot let state: Option<VfioCommonState> = snapshot
.as_ref() .as_ref()
.map(|s| s.to_state()) .map(|s| s.to_versioned_state())
.transpose() .transpose()
.map_err(|e| { .map_err(|e| {
VfioPciError::RetrieveVfioCommonState(anyhow!( VfioPciError::RetrieveVfioCommonState(anyhow!(
@@ -517,20 +477,20 @@ impl VfioCommon {
e e
)) ))
})?; })?;
let msi_state = let msi_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSI_CONFIG_ID)
vm_migration::state_from_id(snapshot.as_ref(), MSI_CONFIG_ID).map_err(|e| { .map_err(|e| {
VfioPciError::RetrieveMsiConfigState(anyhow!( VfioPciError::RetrieveMsiConfigState(anyhow!(
"Failed to get MsiConfigState from Snapshot: {}", "Failed to get MsiConfigState from Snapshot: {}",
e e
)) ))
})?; })?;
let msix_state = let msix_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSIX_CONFIG_ID)
vm_migration::state_from_id(snapshot.as_ref(), MSIX_CONFIG_ID).map_err(|e| { .map_err(|e| {
VfioPciError::RetrieveMsixConfigState(anyhow!( VfioPciError::RetrieveMsixConfigState(anyhow!(
"Failed to get MsixConfigState from Snapshot: {}", "Failed to get MsixConfigState from Snapshot: {}",
e e
)) ))
})?; })?;
if let Some(state) = state.as_ref() { if let Some(state) = state.as_ref() {
vfio_common.set_state(state, msi_state, msix_state)?; vfio_common.set_state(state, msi_state, msix_state)?;
@@ -899,15 +859,15 @@ impl VfioCommon {
} }
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) { pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
let mut cap_iter = self let mut cap_next = self
.vfio_wrapper .vfio_wrapper
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET); .read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
let mut pci_express_cap_found = false; let mut pci_express_cap_found = false;
let mut power_management_cap_found = false; let mut power_management_cap_found = false;
while cap_iter != 0 { while cap_next != 0 {
let cap_id = self.vfio_wrapper.read_config_byte(cap_iter.into()); let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
match PciCapabilityId::from(cap_id) { match PciCapabilityId::from(cap_id) {
PciCapabilityId::MessageSignalledInterrupts => { PciCapabilityId::MessageSignalledInterrupts => {
@@ -915,8 +875,8 @@ impl VfioCommon {
if irq_info.count > 0 { if irq_info.count > 0 {
// Parse capability only if the VFIO device // Parse capability only if the VFIO device
// supports MSI. // supports MSI.
let msg_ctl = self.parse_msi_capabilities(cap_iter); let msg_ctl = self.parse_msi_capabilities(cap_next);
self.initialize_msi(msg_ctl, cap_iter as u32, None); self.initialize_msi(msg_ctl, cap_next as u32, None);
} }
} }
} }
@@ -926,8 +886,8 @@ impl VfioCommon {
if irq_info.count > 0 { if irq_info.count > 0 {
// Parse capability only if the VFIO device // Parse capability only if the VFIO device
// supports MSI-X. // supports MSI-X.
let msix_cap = self.parse_msix_capabilities(cap_iter); let msix_cap = self.parse_msix_capabilities(cap_next);
self.initialize_msix(msix_cap, cap_iter as u32, bdf, None); self.initialize_msix(msix_cap, cap_next as u32, bdf, None);
} }
} }
} }
@@ -936,16 +896,7 @@ impl VfioCommon {
_ => {} _ => {}
}; };
let cap_next = self.vfio_wrapper.read_config_byte((cap_iter + 1).into()); cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
if cap_next == 0 {
break;
}
cap_iter = cap_next;
}
if let Some(clique_id) = self.x_nv_gpudirect_clique {
self.add_nv_gpudirect_clique_cap(cap_iter, clique_id);
} }
if pci_express_cap_found && power_management_cap_found { if pci_express_cap_found && power_management_cap_found {
@@ -953,37 +904,6 @@ impl VfioCommon {
} }
} }
fn add_nv_gpudirect_clique_cap(&mut self, cap_iter: u8, clique_id: u8) {
// Turing, Ampere, Hopper, and Lovelace GPUs have dedicated space
// at 0xD4 for this capability.
let cap_offset = 0xd4u32;
let reg_idx = (cap_iter / 4) as usize;
self.patches.insert(
reg_idx,
ConfigPatch {
mask: 0x0000_ff00,
patch: cap_offset << 8,
},
);
let reg_idx = (cap_offset / 4) as usize;
self.patches.insert(
reg_idx,
ConfigPatch {
mask: 0xffff_ffff,
patch: 0x50080009u32,
},
);
self.patches.insert(
reg_idx + 1,
ConfigPatch {
mask: 0xffff_ffff,
patch: u32::from(clique_id) << 19 | 0x5032,
},
);
}
fn parse_extended_capabilities(&mut self) { fn parse_extended_capabilities(&mut self) {
let mut current_offset = PCI_CONFIG_EXTENDED_CAPABILITY_OFFSET; let mut current_offset = PCI_CONFIG_EXTENDED_CAPABILITY_OFFSET;
@@ -1382,7 +1302,7 @@ impl Snapshottable for VfioCommon {
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_common_snapshot = Snapshot::new_from_state(&self.state())?; let mut vfio_common_snapshot = Snapshot::new_from_versioned_state(&self.state())?;
// Snapshot PciConfiguration // Snapshot PciConfiguration
vfio_common_snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?); vfio_common_snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
@@ -1431,7 +1351,6 @@ impl VfioPciDevice {
bdf: PciBdf, bdf: PciBdf,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>, memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
snapshot: Option<Snapshot>, snapshot: Option<Snapshot>,
x_nv_gpudirect_clique: Option<u8>,
) -> Result<Self, VfioPciError> { ) -> Result<Self, VfioPciError> {
let device = Arc::new(device); let device = Arc::new(device);
device.reset(); device.reset();
@@ -1445,7 +1364,6 @@ impl VfioPciDevice {
&PciVfioSubclass::VfioSubclass, &PciVfioSubclass::VfioSubclass,
bdf, bdf,
vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID), vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
x_nv_gpudirect_clique,
)?; )?;
let vfio_pci_device = VfioPciDevice { let vfio_pci_device = VfioPciDevice {
@@ -1653,16 +1571,6 @@ impl VfioPciDevice {
self.vm self.vm
.create_user_memory_region(mem_region) .create_user_memory_region(mem_region)
.map_err(VfioPciError::CreateUserMemoryRegion)?; .map_err(VfioPciError::CreateUserMemoryRegion)?;
if !self.iommu_attached {
self.container
.vfio_dma_map(
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
)
.map_err(VfioPciError::DmaMap)?;
}
} }
} }
} }
@@ -1673,16 +1581,6 @@ impl VfioPciDevice {
pub fn unmap_mmio_regions(&mut self) { pub fn unmap_mmio_regions(&mut self) {
for region in self.common.mmio_regions.iter() { for region in self.common.mmio_regions.iter() {
for user_memory_region in region.user_memory_regions.iter() { for user_memory_region in region.user_memory_regions.iter() {
// Unmap from vfio container
if !self.iommu_attached {
if let Err(e) = self
.container
.vfio_dma_unmap(user_memory_region.start, user_memory_region.size)
{
error!("Could not unmap mmio region from vfio container: {}", e);
}
}
// Remove region // Remove region
let r = self.vm.make_user_memory_region( let r = self.vm.make_user_memory_region(
user_memory_region.slot, user_memory_region.slot,
@@ -1922,80 +1820,3 @@ impl Snapshottable for VfioPciDevice {
} }
impl Transportable for VfioPciDevice {} impl Transportable for VfioPciDevice {}
impl Migratable for VfioPciDevice {} impl Migratable for VfioPciDevice {}
/// This structure implements the ExternalDmaMapping trait. It is meant to
/// be used when the caller tries to provide a way to update the mappings
/// associated with a specific VFIO container.
pub struct VfioDmaMapping<M: GuestAddressSpace> {
container: Arc<VfioContainer>,
memory: Arc<M>,
mmio_regions: Arc<Mutex<Vec<MmioRegion>>>,
}
impl<M: GuestAddressSpace> VfioDmaMapping<M> {
/// Create a DmaMapping object.
/// # Parameters
/// * `container`: VFIO container object.
/// * `memory`: guest memory to mmap.
/// * `mmio_regions`: mmio_regions to mmap.
pub fn new(
container: Arc<VfioContainer>,
memory: Arc<M>,
mmio_regions: Arc<Mutex<Vec<MmioRegion>>>,
) -> Self {
VfioDmaMapping {
container,
memory,
mmio_regions,
}
}
}
impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioDmaMapping<M> {
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), io::Error> {
let mem = self.memory.memory();
let guest_addr = GuestAddress(gpa);
let user_addr = if mem.check_range(guest_addr, size as usize) {
match mem.get_host_address(guest_addr) {
Ok(t) => t as u64,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("unable to retrieve user address for gpa 0x{gpa:x} from guest memory region: {e}")
));
}
}
} else if self.mmio_regions.lock().unwrap().check_range(gpa, size) {
self.mmio_regions.lock().unwrap().find_user_address(gpa)?
} else {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("failed to locate guest address 0x{gpa:x} in guest memory"),
));
};
self.container
.vfio_dma_map(iova, size, user_addr)
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!(
"failed to map memory for VFIO container, \
iova 0x{iova:x}, gpa 0x{gpa:x}, size 0x{size:x}: {e:?}"
),
)
})
}
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), io::Error> {
self.container.vfio_dma_unmap(iova, size).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!(
"failed to unmap memory for VFIO container, \
iova 0x{iova:x}, size 0x{size:x}: {e:?}"
),
)
})
}
}

View File

@@ -94,7 +94,6 @@ impl VfioUserPciDevice {
&PciVfioUserSubclass::VfioUserSubclass, &PciVfioUserSubclass::VfioUserSubclass,
bdf, bdf,
vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID), vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
None,
) )
.map_err(VfioUserPciDeviceError::CreateVfioCommon)?; .map_err(VfioUserPciDeviceError::CreateVfioCommon)?;

View File

@@ -6,10 +6,10 @@ edition = "2021"
build = "../build.rs" build = "../build.rs"
[dependencies] [dependencies]
clap = { version = "4.5.4", features = ["wrap_help"] } clap = { version = "4.4.7", features = ["wrap_help"] }
dirs = "5.0.1" dirs = "5.0.0"
serde = { version = "1.0.197", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_json = "1.0.115" serde_json = "1.0.107"
test_infra = { path = "../test_infra" } test_infra = { path = "../test_infra" }
thiserror = "1.0.58" thiserror = "1.0.40"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -8,6 +8,7 @@
use crate::{mean, PerformanceTestControl}; use crate::{mean, PerformanceTestControl};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use std::string::String;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use test_infra::Error as InfraError; use test_infra::Error as InfraError;

View File

@@ -4,8 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
epoll = "4.3.3" libc = "0.2.147"
libc = "0.2.153" log = "0.4.20"
log = "0.4.21" thiserror = "1.0.40"
thiserror = "1.0.58"
vmm-sys-util = "0.12.1" vmm-sys-util = "0.12.1"

View File

@@ -1,526 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2023 Crusoe Energy Systems LLC
// SPDX-License-Identifier: Apache-2.0
use crate::{RateLimiter, TokenType};
use core::panic::AssertUnwindSafe;
use std::fs::File;
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::result;
use std::sync::{Arc, Mutex};
use std::thread;
use thiserror::Error;
use vmm_sys_util::eventfd::EventFd;
/// Errors associated with rate-limiter group.
#[derive(Debug, Error)]
pub enum Error {
/// Cannot create thread
#[error("Error spawning rate-limiter thread {0}")]
ThreadSpawn(#[source] io::Error),
/// Cannot create epoll context.
#[error("Error creating epoll context: {0}")]
Epoll(#[source] io::Error),
/// Cannot create EventFd.
#[error("Error creating EventFd: {0}")]
EventFd(#[source] io::Error),
/// Cannot create RateLimiter.
#[error("Error creating RateLimiter: {0}")]
RateLimiter(#[source] io::Error),
/// Cannot read from EventFd.
#[error("Error reading from EventFd: {0}")]
EventFdRead(#[source] io::Error),
/// Cannot write to EventFd.
#[error("Error writing to EventFd: {0}")]
EventFdWrite(#[source] io::Error),
}
/// The RateLimiterGroupHandle is a handle to a RateLimiterGroup that may be
/// used in exactly the same way as the RateLimiter type. When the RateLimiter
/// within a RateLimiterGroup is unblocked, each RateLimiterGroupHandle will
/// be notified.
pub struct RateLimiterGroupHandle {
eventfd: Arc<EventFd>,
inner: Arc<RateLimiterGroupInner>,
}
impl RateLimiterGroupHandle {
fn new(inner: Arc<RateLimiterGroupInner>) -> result::Result<Self, Error> {
let eventfd = Arc::new(EventFd::new(0).map_err(Error::EventFd)?);
inner.handles.lock().unwrap().push(eventfd.clone());
Ok(Self { eventfd, inner })
}
/// Attempts to consume tokens and returns whether that is possible.
///
/// If rate limiting is disabled on provided `token_type`, this function will always succeed.
pub fn consume(&self, tokens: u64, token_type: TokenType) -> bool {
self.inner.rate_limiter.consume(tokens, token_type)
}
/// Adds tokens of `token_type` to their respective bucket.
///
/// Can be used to *manually* add tokens to a bucket. Useful for reverting a
/// `consume()` if needed.
pub fn manual_replenish(&self, tokens: u64, token_type: TokenType) {
self.inner.rate_limiter.manual_replenish(tokens, token_type)
}
/// This function needs to be called every time there is an event on the
/// FD provided by this object's `AsRawFd` trait implementation.
///
/// # Errors
///
/// If the rate limiter is disabled or is not blocked, an error is returned.
pub fn event_handler(&self) -> Result<(), Error> {
self.eventfd.read().map_err(Error::EventFdRead).map(|_| ())
}
/// Returns whether this rate limiter is blocked.
///
/// The limiter 'blocks' when a `consume()` operation fails because there was not enough
/// budget for it.
/// An event will be generated on the exported FD when the limiter 'unblocks'.
pub fn is_blocked(&self) -> bool {
self.inner.rate_limiter.is_blocked()
}
}
impl Clone for RateLimiterGroupHandle {
fn clone(&self) -> Self {
RateLimiterGroupHandle::new(self.inner.clone()).unwrap()
}
}
impl AsRawFd for RateLimiterGroupHandle {
fn as_raw_fd(&self) -> RawFd {
self.eventfd.as_raw_fd()
}
}
impl Drop for RateLimiterGroupHandle {
fn drop(&mut self) {
let mut handles = self.inner.handles.lock().unwrap();
let index = handles
.iter()
.position(|handle| handle.as_raw_fd() == self.eventfd.as_raw_fd())
.expect("RateLimiterGroupHandle must be subscribed to RateLimiterGroup");
handles.remove(index);
}
}
struct RateLimiterGroupInner {
id: String,
rate_limiter: RateLimiter,
handles: Mutex<Vec<Arc<EventFd>>>,
}
/// A RateLimiterGroup is an extension of RateLimiter that enables rate-limiting
/// the aggregate io consumption of multiple consumers.
pub struct RateLimiterGroup {
inner: Arc<RateLimiterGroupInner>,
epoll_file: File,
kill_evt: EventFd,
epoll_thread: Option<thread::JoinHandle<()>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u64)]
enum EpollDispatch {
Kill = 1,
Unblocked = 2,
Unknown,
}
impl From<u64> for EpollDispatch {
fn from(v: u64) -> Self {
use EpollDispatch::*;
match v {
1 => Kill,
2 => Unblocked,
_ => Unknown,
}
}
}
impl RateLimiterGroup {
/// Create a new RateLimiterGroup.
pub fn new(
id: &str,
bytes_total_capacity: u64,
bytes_one_time_burst: u64,
bytes_complete_refill_time_ms: u64,
ops_total_capacity: u64,
ops_one_time_burst: u64,
ops_complete_refill_time_ms: u64,
) -> result::Result<Self, Error> {
let rate_limiter = RateLimiter::new(
bytes_total_capacity,
bytes_one_time_burst,
bytes_complete_refill_time_ms,
ops_total_capacity,
ops_one_time_burst,
ops_complete_refill_time_ms,
)
.map_err(Error::RateLimiter)?;
let epoll_fd = epoll::create(true).map_err(Error::Epoll)?;
let kill_evt = EventFd::new(0).map_err(Error::EventFd)?;
epoll::ctl(
epoll_fd,
epoll::ControlOptions::EPOLL_CTL_ADD,
kill_evt.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Kill as u64),
)
.map_err(Error::Epoll)?;
epoll::ctl(
epoll_fd,
epoll::ControlOptions::EPOLL_CTL_ADD,
rate_limiter.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Unblocked as u64),
)
.map_err(Error::Epoll)?;
// Use 'File' to enforce closing on 'epoll_fd'
// SAFETY: epoll_fd is valid
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
Ok(Self {
inner: Arc::new(RateLimiterGroupInner {
id: id.to_string(),
rate_limiter,
handles: Mutex::new(Vec::new()),
}),
epoll_file,
kill_evt,
epoll_thread: None,
})
}
/// Create a new RateLimiterGroupHandle.
pub fn new_handle(&self) -> result::Result<RateLimiterGroupHandle, Error> {
RateLimiterGroupHandle::new(self.inner.clone())
}
/// Start a worker thread to broadcast an event to each RateLimiterGroupHandle
/// when the RateLimiter becomes unblocked.
pub fn start_thread(&mut self, exit_evt: EventFd) -> result::Result<(), Error> {
let inner = self.inner.clone();
let epoll_fd = self.epoll_file.as_raw_fd();
thread::Builder::new()
.name(format!("rate-limit-group-{}", inner.id))
.spawn(move || {
let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
const EPOLL_EVENTS_LEN: usize = 2;
let mut events =
[epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
loop {
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
Ok(res) => res,
Err(e) => {
if e.kind() == io::ErrorKind::Interrupted {
continue;
} else {
return Err(Error::Epoll(e));
}
}
};
for event in events.iter().take(num_events) {
let dispatch_event: EpollDispatch = event.data.into();
match dispatch_event {
EpollDispatch::Unknown => {
let event = event.data;
warn!("Unknown rate-limiter loop event: {}", event);
}
EpollDispatch::Unblocked => {
inner.rate_limiter.event_handler().unwrap();
let handles = inner.handles.lock().unwrap();
for handle in handles.iter() {
handle.write(1).map_err(Error::EventFdWrite)?
}
}
EpollDispatch::Kill => {
info!(
"KILL_EVENT received, stopping rate-limit-group epoll loop"
);
return Ok(());
}
}
}
}
}));
match res {
Ok(res) => {
if let Err(e) = res {
error!("Error running rate-limit-group worker: {:?}", e);
exit_evt.write(1).unwrap();
}
}
Err(_) => {
error!("rate-limit-group worker panicked");
exit_evt.write(1).unwrap();
}
};
})
.map(|thread| self.epoll_thread.insert(thread))
.map_err(Error::ThreadSpawn)?;
Ok(())
}
}
impl Drop for RateLimiterGroup {
fn drop(&mut self) {
self.kill_evt.write(1).unwrap();
if let Some(t) = self.epoll_thread.take() {
if let Err(e) = t.join() {
error!("Error joining thread: {:?}", e);
}
}
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::RateLimiterGroupHandle;
use crate::{group::RateLimiterGroup, TokenBucket, TokenType, REFILL_TIMER_INTERVAL_MS};
use std::{os::fd::AsRawFd, thread, time::Duration};
use vmm_sys_util::eventfd::EventFd;
impl RateLimiterGroupHandle {
pub fn bandwidth(&self) -> Option<TokenBucket> {
let guard = self.inner.rate_limiter.inner.lock().unwrap();
guard.bandwidth.clone()
}
pub fn ops(&self) -> Option<TokenBucket> {
let guard = self.inner.rate_limiter.inner.lock().unwrap();
guard.ops.clone()
}
}
#[test]
fn test_rate_limiter_group_new() {
let l = RateLimiterGroup::new("test", 1000, 1001, 1002, 1003, 1004, 1005).unwrap();
let h = l.new_handle().unwrap();
let bw = h.bandwidth().unwrap();
assert_eq!(bw.capacity(), 1000);
assert_eq!(bw.one_time_burst(), 1001);
assert_eq!(bw.refill_time_ms(), 1002);
assert_eq!(bw.budget(), 1000);
let ops = h.ops().unwrap();
assert_eq!(ops.capacity(), 1003);
assert_eq!(ops.one_time_burst(), 1004);
assert_eq!(ops.refill_time_ms(), 1005);
assert_eq!(ops.budget(), 1003);
}
#[test]
fn test_rate_limiter_group_manual_replenish() {
// rate limiter with limit of 1000 bytes/s and 1000 ops/s
let l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
let h = l.new_handle().unwrap();
// consume 123 bytes
assert!(h.consume(123, TokenType::Bytes));
h.manual_replenish(23, TokenType::Bytes);
{
let bytes_tb = h.bandwidth().unwrap();
assert_eq!(bytes_tb.budget(), 900);
}
// consume 123 ops
assert!(h.consume(123, TokenType::Ops));
h.manual_replenish(23, TokenType::Ops);
{
let bytes_tb = h.ops().unwrap();
assert_eq!(bytes_tb.budget(), 900);
}
}
#[test]
fn test_rate_limiter_group_bandwidth() {
// rate limiter with limit of 1000 bytes/s
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 0, 0, 0).unwrap();
l.start_thread(EventFd::new(0).unwrap()).unwrap();
let h = l.new_handle().unwrap();
// limiter should not be blocked
assert!(!h.is_blocked());
// raw FD for this disabled should be valid
assert!(h.as_raw_fd() > 0);
// ops/s limiter should be disabled so consume(whatever) should work
assert!(h.consume(u64::max_value(), TokenType::Ops));
// do full 1000 bytes
assert!(h.consume(1000, TokenType::Bytes));
// try and fail on another 100
assert!(!h.consume(100, TokenType::Bytes));
// since consume failed, limiter should be blocked now
assert!(h.is_blocked());
// wait half the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// limiter should still be blocked
assert!(h.is_blocked());
// wait the other half of the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// the timer_fd should have an event on it by now
assert!(h.event_handler().is_ok());
// limiter should now be unblocked
assert!(!h.is_blocked());
// try and succeed on another 100 bytes this time
assert!(h.consume(100, TokenType::Bytes));
}
#[test]
fn test_rate_limiter_group_ops() {
// rate limiter with limit of 1000 ops/s
let mut l = RateLimiterGroup::new("test", 0, 0, 0, 1000, 0, 1000).unwrap();
l.start_thread(EventFd::new(0).unwrap()).unwrap();
let h = l.new_handle().unwrap();
// limiter should not be blocked
assert!(!h.is_blocked());
// raw FD for this disabled should be valid
assert!(h.as_raw_fd() > 0);
// bytes/s limiter should be disabled so consume(whatever) should work
assert!(h.consume(u64::max_value(), TokenType::Bytes));
// do full 1000 ops
assert!(h.consume(1000, TokenType::Ops));
// try and fail on another 100
assert!(!h.consume(100, TokenType::Ops));
// since consume failed, limiter should be blocked now
assert!(h.is_blocked());
// wait half the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// limiter should still be blocked
assert!(h.is_blocked());
// wait the other half of the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// the timer_fd should have an event on it by now
assert!(h.event_handler().is_ok());
// limiter should now be unblocked
assert!(!h.is_blocked());
// try and succeed on another 100 ops this time
assert!(h.consume(100, TokenType::Ops));
}
#[test]
fn test_rate_limiter_group_full() {
// rate limiter with limit of 1000 bytes/s and 1000 ops/s
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
l.start_thread(EventFd::new(0).unwrap()).unwrap();
let h = l.new_handle().unwrap();
// limiter should not be blocked
assert!(!h.is_blocked());
// raw FD for this disabled should be valid
assert!(h.as_raw_fd() > 0);
// do full 1000 bytes
assert!(h.consume(1000, TokenType::Ops));
// do full 1000 bytes
assert!(h.consume(1000, TokenType::Bytes));
// try and fail on another 100 ops
assert!(!h.consume(100, TokenType::Ops));
// try and fail on another 100 bytes
assert!(!h.consume(100, TokenType::Bytes));
// since consume failed, limiter should be blocked now
assert!(h.is_blocked());
// wait half the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// limiter should still be blocked
assert!(h.is_blocked());
// wait the other half of the timer period
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
// the timer_fd should have an event on it by now
assert!(h.event_handler().is_ok());
// limiter should now be unblocked
assert!(!h.is_blocked());
// try and succeed on another 100 ops this time
assert!(h.consume(100, TokenType::Ops));
// try and succeed on another 100 bytes this time
assert!(h.consume(100, TokenType::Bytes));
}
#[test]
fn test_rate_limiter_group_overconsumption() {
// initialize the rate limiter
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
l.start_thread(EventFd::new(0).unwrap()).unwrap();
let h = l.new_handle().unwrap();
// try to consume 2.5x the bucket size
// we are "borrowing" 1.5x the bucket size in tokens since
// the bucket is full
assert!(h.consume(2500, TokenType::Bytes));
// check that even after a whole second passes, the rate limiter
// is still blocked
thread::sleep(Duration::from_millis(1000));
assert!(h.is_blocked());
// after 1.5x the replenish time has passed, the rate limiter
// is available again
thread::sleep(Duration::from_millis(500));
assert!(h.event_handler().is_ok());
assert!(!h.is_blocked());
// reset the rate limiter
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
l.start_thread(EventFd::new(0).unwrap()).unwrap();
let h = l.new_handle().unwrap();
// try to consume 1.5x the bucket size
// we are "borrowing" 1.5x the bucket size in tokens since
// the bucket is full, should arm the timer to 0.5x replenish
// time, which is 500 ms
assert!(h.consume(1500, TokenType::Bytes));
// check that after more than the minimum refill time,
// the rate limiter is still blocked
thread::sleep(Duration::from_millis(200));
assert!(h.is_blocked());
// try to consume some tokens, which should fail as the timer
// is still active
assert!(!h.consume(100, TokenType::Bytes));
assert!(h.is_blocked());
// check that after the minimum refill time, the timer was not
// overwritten and the rate limiter is still blocked from the
// borrowing we performed earlier
thread::sleep(Duration::from_millis(100));
assert!(h.is_blocked());
assert!(!h.consume(100, TokenType::Bytes));
// after waiting out the full duration, rate limiter should be
// available again
thread::sleep(Duration::from_millis(200));
assert!(h.event_handler().is_ok());
assert!(!h.is_blocked());
assert!(h.consume(100, TokenType::Bytes));
}
}

View File

@@ -53,9 +53,6 @@ use std::sync::Mutex;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use vmm_sys_util::timerfd::TimerFd; use vmm_sys_util::timerfd::TimerFd;
/// Module for group rate limiting.
pub mod group;
#[derive(Debug)] #[derive(Debug)]
/// Describes the errors that may occur while handling rate limiter events. /// Describes the errors that may occur while handling rate limiter events.
pub enum Error { pub enum Error {
@@ -522,6 +519,7 @@ pub(crate) mod tests {
use super::*; use super::*;
use std::fmt; use std::fmt;
use std::thread; use std::thread;
use std::time::Duration;
impl TokenBucket { impl TokenBucket {
// Resets the token bucket: budget set to max capacity and last-updated set to now. // Resets the token bucket: budget set to max capacity and last-updated set to now.

View File

@@ -1,27 +1,12 @@
- [v39.0](#v390) - [v37.1](#v371)
- [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)
- [Contributors](#contributors)
- [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)
- [Optimized Boot Time with Parallel Memory Prefault](#optimized-boot-time-with-parallel-memory-prefault)
- [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-1)
- [Contributors](#contributors-1)
- [v37.0](#v370) - [v37.0](#v370)
- [Long Term Support (LTS) Release](#long-term-support-lts-release) - [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) - [Improved VFIO Device Passthrough with Multiple PCI Segments](#improved-vfio-device-passthrough-with-multiple-pci-segments)
- [Configurable Named TAP Devices](#configurable-named-tap-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) - [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) - [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
- [Notable Bug Fixes](#notable-bug-fixes-2) - [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors-2) - [Contributors](#contributors)
- [v36.0](#v360) - [v36.0](#v360)
- [Command Line Changes](#command-line-changes) - [Command Line Changes](#command-line-changes)
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli) - [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
@@ -30,31 +15,31 @@
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port) - [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
- [AIO Backend for Block Devices](#aio-backend-for-block-devices) - [AIO Backend for Block Devices](#aio-backend-for-block-devices)
- [Documentation Improvements](#documentation-improvements) - [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-3) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-3) - [Contributors](#contributors-1)
- [v35.0](#v350) - [v35.0](#v350)
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63) - [`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) - [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) - [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
- [Notable Bug Fixes](#notable-bug-fixes-4) - [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-4) - [Contributors](#contributors-2)
- [v34.0](#v340) - [v34.0](#v340)
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support) - [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump) - [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files) - [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump) - [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
- [Notable Bug Fixes](#notable-bug-fixes-5) - [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-5) - [Contributors](#contributors-3)
- [v33.0](#v330) - [v33.0](#v330)
- [D-Bus based API](#d-bus-based-api) - [D-Bus based API](#d-bus-based-api)
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64) - [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-6) - [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-6) - [Contributors](#contributors-4)
- [v32.0](#v320) - [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit) - [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes) - [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes-7) - [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-7) - [Contributors](#contributors-5)
- [v31.1](#v311) - [v31.1](#v311)
- [v31.0](#v310) - [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables) - [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
@@ -62,15 +47,15 @@
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler) - [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile) - [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements-1) - [Documentation Improvements](#documentation-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-8) - [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-8) - [Contributors](#contributors-6)
- [v30.0](#v300) - [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size) - [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support) - [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support) - [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-2) - [Documentation Improvements](#documentation-improvements-2)
- [Notable Bug Fixes](#notable-bug-fixes-9) - [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-9) - [Contributors](#contributors-7)
- [v28.2](#v282) - [v28.2](#v282)
- [v29.0](#v290) - [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm) - [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -80,10 +65,10 @@
- [`AArch64` Documentation Integration](#aarch64-documentation-integration) - [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement) - [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control) - [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes-10) - [Notable Bug Fixes](#notable-bug-fixes-8)
- [Removals](#removals) - [Removals](#removals)
- [Deprecations](#deprecations) - [Deprecations](#deprecations)
- [Contributors](#contributors-10) - [Contributors](#contributors-8)
- [v28.1](#v281) - [v28.1](#v281)
- [v28.0](#v280) - [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder) - [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -91,9 +76,9 @@
- [Virtualised TPM Support](#virtualised-tpm-support) - [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support) - [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved) - [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes-11) - [Notable Bug Fixes](#notable-bug-fixes-9)
- [Removals](#removals-1) - [Removals](#removals-1)
- [Contributors](#contributors-11) - [Contributors](#contributors-9)
- [v27.0](#v270) - [v27.0](#v270)
- [Community Engagement](#community-engagement) - [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages) - [Prebuilt Packages](#prebuilt-packages)
@@ -102,41 +87,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags) - [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading) - [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64) - [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-12) - [Notable Bug Fixes](#notable-bug-fixes-10)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-12) - [Contributors](#contributors-10)
- [v26.0](#v260) - [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform) - [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support) - [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
- [Notable Bug Fixes](#notable-bug-fixes-13) - [Notable Bug Fixes](#notable-bug-fixes-11)
- [Deprecations](#deprecations-2) - [Deprecations](#deprecations-2)
- [Removals](#removals-2) - [Removals](#removals-2)
- [Contributors](#contributors-13) - [Contributors](#contributors-11)
- [v25.0](#v250) - [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1) - [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support) - [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-14) - [Notable Bug Fixes](#notable-bug-fixes-12)
- [Removals](#removals-3) - [Removals](#removals-3)
- [Contributors](#contributors-14) - [Contributors](#contributors-12)
- [v24.0](#v240) - [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu) - [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness) - [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support) - [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number) - [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-15) - [Notable Bug Fixes](#notable-bug-fixes-13)
- [Notable Improvements](#notable-improvements) - [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3) - [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website) - [New on the Website](#new-on-the-website)
- [Contributors](#contributors-15) - [Contributors](#contributors-13)
- [v23.1](#v231) - [v23.1](#v231)
- [v23.0](#v230) - [v23.0](#v230)
- [vDPA Support](#vdpa-support) - [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list) - [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements) - [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support) - [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-16) - [Notable Bug Fixes](#notable-bug-fixes-14)
- [Deprecations](#deprecations-4) - [Deprecations](#deprecations-4)
- [Contributors](#contributors-16) - [Contributors](#contributors-14)
- [v22.1](#v221) - [v22.1](#v221)
- [v22.0](#v220) - [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support) - [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -147,13 +132,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64) - [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license) - [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd) - [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-17) - [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-17) - [Contributors](#contributors-15)
- [v21.0](#v210) - [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade) - [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515) - [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-18) - [Notable Bug fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-18) - [Contributors](#contributors-16)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -162,8 +147,8 @@
- [Improved VFIO support](#improved-vfio-support) - [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code) - [Safer code](#safer-code)
- [Extended documentation](#extended-documentation) - [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-19) - [Notable bug fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-19) - [Contributors](#contributors-17)
- [v19.0](#v190) - [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console) - [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations) - [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -171,8 +156,8 @@
- [Live migration enhancements](#live-migration-enhancements) - [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user) - [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu) - [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-20) - [Notable bug fixes](#notable-bug-fixes-18)
- [Contributors](#contributors-20) - [Contributors](#contributors-18)
- [v18.0](#v180) - [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support) - [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices) - [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -182,23 +167,23 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor) - [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support) - [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64) - [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-21) - [Notable bug fixes](#notable-bug-fixes-19)
- [Contributors](#contributors-21) - [Contributors](#contributors-19)
- [v17.0](#v170) - [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi) - [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend) - [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices) - [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support) - [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices) - [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-22) - [Notable bug fixes](#notable-bug-fixes-20)
- [Contributors](#contributors-22) - [Contributors](#contributors-20)
- [v16.0](#v160) - [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support) - [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support) - [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support) - [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-23) - [Notable bug fixes](#notable-bug-fixes-21)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-23) - [Contributors](#contributors-21)
- [v15.0](#v150) - [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees) - [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting) - [Network device rate limiting](#network-device-rate-limiting)
@@ -206,7 +191,7 @@
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter) - [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes) - [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-5) - [Deprecations](#deprecations-5)
- [Contributors](#contributors-24) - [Contributors](#contributors-22)
- [v0.14.1](#v0141) - [v0.14.1](#v0141)
- [v0.14.0](#v0140) - [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring) - [Structured event monitoring](#structured-event-monitoring)
@@ -216,7 +201,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console) - [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting) - [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-6) - [Deprecations](#deprecations-6)
- [Contributors](#contributors-25) - [Contributors](#contributors-23)
- [v0.13.0](#v0130) - [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support) - [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support) - [Improved huge page support](#improved-huge-page-support)
@@ -224,13 +209,13 @@
- [VHD disk image support](#vhd-disk-image-support) - [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading) - [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button) - [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-26) - [Contributors](#contributors-24)
- [v0.12.0](#v0120) - [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements) - [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning) - [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend) - [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api) - [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-27) - [Contributors](#contributors-25)
- [v0.11.0](#v0110) - [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block) - [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support) - [Windows Guest Support](#windows-guest-support)
@@ -242,15 +227,15 @@
- [Default Log Level Changed](#default-log-level-changed) - [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added) - [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support) - [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-24) - [Notable Bug Fixes](#notable-bug-fixes-22)
- [Contributors](#contributors-28) - [Contributors](#contributors-26)
- [v0.10.0](#v0100) - [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors) - [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones) - [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control) - [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-25) - [Notable Bug Fixes](#notable-bug-fixes-23)
- [Contributors](#contributors-29) - [Contributors](#contributors-27)
- [v0.9.0](#v090) - [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support) - [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics) - [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -263,17 +248,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support) - [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support) - [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-26) - [Notable Bug Fixes](#notable-bug-fixes-24)
- [Contributors](#contributors-30) - [Contributors](#contributors-28)
- [v0.8.0](#v080) - [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support) - [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support) - [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests) - [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices) - [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements) - [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-27) - [Notable Bug Fixes](#notable-bug-fixes-25)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-31) - [Contributors](#contributors-29)
- [v0.7.0](#v070) - [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug) - [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support) - [Alternative `libc` Support](#alternative-libc-support)
@@ -283,14 +268,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing) - [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support) - [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1) - [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-32) - [Contributors](#contributors-30)
- [v0.6.0](#v060) - [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug) - [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements) - [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading) - [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface) - [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot) - [PVH Boot](#pvh-boot)
- [Contributors](#contributors-33) - [Contributors](#contributors-31)
- [v0.5.1](#v051) - [v0.5.1](#v051)
- [v0.5.0](#v050) - [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing) - [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -298,7 +283,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework) - [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools) - [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration) - [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-34) - [Contributors](#contributors-32)
- [v0.4.0](#v040) - [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition) - [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation) - [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -307,7 +292,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default) - [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming) - [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization) - [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-35) - [Contributors](#contributors-33)
- [v0.3.0](#v030) - [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading) - [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend) - [Network device backend](#network-device-backend)
@@ -334,147 +319,18 @@
- [Unit testing](#unit-testing) - [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization) - [Integration tests parallelization](#integration-tests-parallelization)
# v39.0 # v37.1
This release has been tracked in our [roadmap This is a bug fix release. The following issues have been addressed:
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v39.0. The following user visible changes have been made:
### Variable Sizing of PCI Apertures for Segments
It is now possible to use `--pci-segment` to adjust the aperture size that
devices 32-bit and 64-bit PCI device BARs will be allocated from. Previously
the address space was equally distributed across all the segments which may
leave insufficient space for devices that require a large 32-bit space. With
this change the weighting per segment can be adjusted. (#6387)
### Direct Booting with bzImages
Support for directly booting Linux from bzImages has been added.(#6200)
### Support for NVIDIA GPUDirect P2P Support
The `x_nv_gpudirect_clique` option was added to `--device` to allow the
configuration of device P2P support with NVIDIA GPUs. (#6235)
### Guest NMI Injection Support
A new API endpoint and `ch-remote` option added for injecting an NMI into the
guest. (#6047)
### Notable Bug Fixes
* Workaround for kernel bug affecting guest IRQ masking on AMD (#6353)
* Correctly cleanup `sigwinch_listener` process (#6208)
* Graceful shutdown of HTTP API thread (#6248, #6247)
* Fix `queue_affinity` option in OpenAPI metadata (#6268)
* Fix documentation to indicate only stream mode is supported by `virtio-vsock`
(#6306)
* Fix `virtio-fs` tag validation (#6358, #6359)
* Add missing `pvpanic` device to OpenAPI metadata (#6372)
* Fixes for nested virtualization with VFIO devices (#6110, #6298, #6297,
#6319)
* Fix for backing file for `virtio-mem` regions with snapshot/restore (#6337,
#6338)
* Explicitly mark FDs used for network devices as invalid across
snapshot/restore (#6332, #6286)
* Improve `event-monitor` events around reboot (#6277, #6274)
* Fix potential deadlock around paused devices during live migration (#6293)
* Fix panic when running `ch-remote` with no subcommand (#6230)
* Fix hotplug of `virtio` devices after snapshot/restore and live migration
(#6326, #6265)
### Contributors
Many thanks to everyone who has contributed to our release:
* Alexandru Matei <alexandru.matei@uipath.com>
* Andrew Carp <acarp@crusoeenergy.com>
* Bo Chen <chen.bo@intel.com>
* Bouke van der Bijl <i@bou.ke>
* Chris Webb <chris@arachsys.com>
* Jinank Jain <jinankjain@microsoft.com>
* Lucas Jacques <contact@lucasjacques.com>
* Muminul Islam <muislam@microsoft.com>
* Nuno Das Neves <nudasnev@microsoft.com>
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Stefan Nuernberger <stefan.nuernberger@cyberus-technology.de>
* Thomas Barrett <tbarrett@crusoeenergy.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <foxywang@tencent.com>
# v38.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v38.0. The following user visible changes have been made:
### Group Rate Limiter on Block Devices
Users now can throttle a group of block devices with the new
`--rate-limiter-group` option. Details can be found from the [I/O
Throttling documentation](docs/io_throttling.md)
### CPU Pinning Support for Block Device Worker Thread
Users now have the option to pin virt-queue threads for block devices
to specific host cpus.
### Optimized Boot Time with Parallel Memory Prefault
The boot time with `prefault` option enabled is optimized via parallel
memory prefault.
### New 'debug-console' Device
A 'debug-console' device is added to provide a user-configurable debug
port for logging guest information. Details can be found from the [Debug
IO Ports documentation](docs/debug-port.md).
### Improved VFIO Device Support
All non-emulated MMIO regions of VFIO devices are now mapped to the VFIO
container, allowing PCIe P2P between all VFIO devices on the same
VM. This is required for a wide variety of multi-GPU workloads involving
GPUDirect P2P (DMA between two GPUs), GPUDirect RDMA (DMA between a GPU
and an IB device).
### Extended CPU Affinity Support
Users now can set the vcpu affinity to a host CPU with index larger
than 255.
### Notable Bug Fixes
* Fix several security advisories from dependencies (#6134, #6141)
* Enable HTT flag to avoid crashing cpu topology enumeration software * Enable HTT flag to avoid crashing cpu topology enumeration software
such as hwloc in the guest (#6146) such as hwloc in the guest (#6146)
* Fix several security advisories from dependencies (#6134, #6141)
* Handle non-power-of-two CPU topology properly (#6062)
* Various bug fixes around `virtio-vsock`(#6080, #6091, #6095)
* Enable nested virtualization on AMD if supported (#6106) * Enable nested virtualization on AMD if supported (#6106)
* Handle non-power-of-two CPU topology properly (#6062)
* Various bug fixes around virtio-vsock(#6080, #6091, #6095)
* Align VFIO devices PCI BARs naturally (#6196) * Align VFIO devices PCI BARs naturally (#6196)
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Bo Chen <chen.bo@intel.com>
* Daniel Farina <daniel@ubicloud.com>
* Jinank Jain <jinankjain@microsoft.com>
* Muminul Islam <muislam@microsoft.com>
* Peteris Rudzusiks <rye@stripe.com>
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Sean Banko <sbanko@crusoeenergy.com>
* Thomas Barrett <tbarrett@crusoeenergy.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <foxywang@tencent.com>
* acarp <acarp@crusoeenergy.com>
# v37.0 # v37.0
This release has been tracked in our [roadmap This release has been tracked in our [roadmap

View File

@@ -1,5 +1,3 @@
# Copyright © 2024 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
# When changing this file don't forget to update the tag name in the # When changing this file don't forget to update the tag name in the
@@ -8,7 +6,7 @@
FROM ubuntu:22.04 as dev FROM ubuntu:22.04 as dev
ARG TARGETARCH ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.74.1" ARG RUST_TOOLCHAIN="1.70.0"
ARG CLH_SRC_DIR="/cloud-hypervisor" ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build" ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry" ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
: ' : '
This script checks if an image is compatible with Cloud Hypervisor. This script checks if an image is compatible with Cloud Hypervisor.
At first, it detects the image type(raw or qcow2), At first, it detects the image type(raw or qcow2),
@@ -8,6 +8,8 @@
a message about the compatibility of the image. a message about the compatibility of the image.
' '
usage="$(basename "$0") [-h] -f -w -- program to check Cloud Hypervisor compatible image usage="$(basename "$0") [-h] -f -w -- program to check Cloud Hypervisor compatible image
where: where:
@@ -16,11 +18,12 @@ where:
-w directory to be used for temporary files" -w directory to be used for temporary files"
function check_command { function check_command {
if ! command -v "$1" &>/dev/null; then if ! command -v $1 &> /dev/null
echo "Command $1 could not be found" then
echo "Command $1 could not be found"
exit 1 exit 1
fi fi
} };
function check_if_root { function check_if_root {
if [ "$EUID" -ne 0 ]; then if [ "$EUID" -ne 0 ]; then
@@ -28,32 +31,27 @@ function check_if_root {
exit 1 exit 1
fi fi
} };
check_if_root check_if_root
working_dir="" working_dir=""
while getopts ':hf:w:' option; do while getopts ':hf:w:' option; do
case "$option" in case "$option" in
h) h) echo "$usage"
echo "$usage" exit
exit ;;
;; f) file_name=$OPTARG
f) ;;
file_name=$OPTARG w) working_dir=$OPTARG
;; ;;
w) :) printf "missing argument for -%s\n" "$OPTARG" >&2
working_dir=$OPTARG echo "$usage" >&2
;; exit 1
:) ;;
printf "missing argument for -%s\n" "$OPTARG" >&2 \?) printf "illegal option: -%s\n" "$OPTARG" >&2
echo "$usage" >&2 echo "$usage" >&2
exit 1 exit 1
;; ;;
\?)
printf "illegal option: -%s\n" "$OPTARG" >&2
echo "$usage" >&2
exit 1
;;
esac esac
done done
@@ -61,64 +59,67 @@ shift $((OPTIND - 1))
if [ -z "${file_name}" ]; then if [ -z "${file_name}" ]; then
echo "You must provide the image file name" echo "You must provide the image file name"
exit 1 exit 1
fi fi
if [[ ! -f ${file_name} ]]; then if [[ ! -f ${file_name} ]]; then
echo "File ${file_name} does not exist" echo "File ${file_name} does not exist"
exit 1 exit 1
fi fi
file_abs_path=$(readlink -m "${file_name}") file_abs_path=`readlink -m ${file_name}`
if [[ "${working_dir}" != "" && ! -d "${working_dir}" ]]; then if [[ "${working_dir}" != "" && ! -d "${working_dir}" ]]; then
echo "Directory ${working_dir} does not exist" echo "Directory ${working_dir} does not exist"
exit 1 exit 1
elif [[ "${working_dir}" == "" ]]; then elif [[ "${working_dir}" == "" ]]; then
working_dir=$(mktemp -d) working_dir=`mktemp -d`
tmp_created=1 tmp_created=1
else else
working_dir=$(readlink -m "${working_dir}") working_dir=`readlink -m ${working_dir}`
fi fi
#get file extension and image type
extension="${file_name##*.}"
filename="${file_name%.*}" filename="${file_name%.*}"
dest_file=${working_dir}/${filename}.raw dest_file=${working_dir}/${filename}.raw
image_type=$(qemu-img info "${file_abs_path}" | grep 'file format:' | awk '{ print $3 }') image_type=$(qemu-img info ${file_abs_path} | grep 'file format:' | awk '{ print $3 }')
echo "Image type detected as ${image_type}" echo "Image type detected as ${image_type}"
if [[ "${image_type}" == "raw" ]]; then if [[ "${image_type}" == "raw" ]]; then
dest_file=${file_abs_path} dest_file=${file_abs_path}
elif [[ "$image_type" == "qcow2" ]]; then elif [[ "$image_type" == "qcow2" ]]; then
if lsmod | grep "nbd" &>/dev/null; then if lsmod | grep "nbd" &> /dev/null ; then
echo "Module nbd is loaded!" echo "Module nbd is loaded!"
else else
echo "Module nbd is not loaded. Trying to load the module" echo "Module nbd is not loaded. Trying to load the module"
modprobe nbd max_part=8
if ! modprobe nbd max_part=8; then if [ $? != 0 ]; then
echo "failed to load nbd module. Exiting" echo "failed to load nbd module. Exiting"
exit 1 exit 1
fi fi
fi fi
check_command qemu-img check_command qemu-img
dest_file=/dev/nbd0 dest_file=/dev/nbd0
qemu-nbd --connect=${dest_file} "${file_abs_path}" --read-only qemu-nbd --connect=${dest_file} ${file_abs_path} --read-only
fi fi
check_command blkid check_command blkid
#get part info #get part info
part_type=$(blkid -o value -s PTTYPE "${dest_file}") part_type=$(blkid -o value -s PTTYPE ${dest_file})
check_command partx check_command partx
nr_partitions=$(partx -g "${dest_file}" | wc -l) nr_partitions=`partx -g ${dest_file} | wc -l`
check_command fdisk check_command fdisk
out=$(fdisk -l "${dest_file}" --bytes | grep -i -A "${nr_partitions}" 'Device' | tail -n +2) out=`fdisk -l ${dest_file} --bytes | grep -i -A ${nr_partitions} 'Device' | tail -n +2`
IFS=' IFS='
' '
i=0 i=0
declare -A lines declare -A liness
for x in $out; do for x in $out ; do
lines[$i]=$x lines[$i]=$x
i=$((i + 1)) i=$((i+1))
done done
declare -A partitions declare -A partitions
@@ -126,86 +127,89 @@ IFS=' '
i=0 i=0
ROWS=${#lines[@]} ROWS=${#lines[@]}
for line in "${lines[@]}"; do for line in "${lines[@]}";
j=0 do
read -a -r str_arr <<<"$line" j=0
for val in "${str_arr[@]}"; do read -a str_arr <<< "$line"
if [[ "$val" != "*" ]]; then for val in "${str_arr[@]}";
partitions[$i, $j]=$val do
j=$((j + 1)) if [[ "$val" != "*" ]]; then
fi partitions[$i,$j]=$val
done j=$((j+1))
i=$((i + 1)) fi
done
i=$((i+1))
done done
COLUMNS=$j COLUMNS=$j
COUNT=${#partitions[@]}
START_ADDRESS_INDEX=1 START_ADDRESS_INDEX=1
FILE_SYS_INDEX2=$((COLUMNS - 1)) FILE_SYS_INDEX2=$((COLUMNS-1))
FILE_SYS_INDEX1=$((COLUMNS - 2)) FILE_SYS_INDEX1=$((COLUMNS-2))
DEVICE_INDEX=0 DEVICE_INDEX=0
# Here we have all the partition info now lets mount and analyze the contents # Here we have all the partition info now lets mount and analyze the contents
for ((i = 0; i < ROWS; i++)); do for ((i=0;i<ROWS;i++)) do
if [[ "$part_type" == "gpt" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then if [[ "$part_type" == "gpt" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then
echo "The image has GPT partitions" echo "The image has GPT partitions"
MOUNT_ROW=$i MOUNT_ROW=$i
break break
elif [[ "$part_type" == "dos" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "" ]]; then elif [[ "$part_type" == "dos" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "" ]]; then
echo "The image has DOS partitions" echo "The image has DOS partitions"
MOUNT_ROW=$i MOUNT_ROW=$i
break break
fi fi
done done
start_address=${partitions[${MOUNT_ROW}, ${START_ADDRESS_INDEX}]} start_address=${partitions[${MOUNT_ROW},${START_ADDRESS_INDEX}]}
offset=$((start_address * 512)) offset=$((start_address*512))
MOUNT_DIR=/mnt/clh-img-check/ MOUNT_DIR=/mnt/clh-img-check/
rm -rf ${MOUNT_DIR} rm -rf ${MOUNT_DIR}
mkdir ${MOUNT_DIR} mkdir ${MOUNT_DIR}
if [[ "${image_type}" == "raw" ]]; then if [[ "${image_type}" == "raw" ]]; then
mount -o ro,loop,offset=$offset "${dest_file}" ${MOUNT_DIR} mount -o ro,loop,offset=$offset ${dest_file} ${MOUNT_DIR}
elif [[ "${image_type}" == "qcow2" ]]; then elif [[ "${image_type}" == "qcow2" ]]; then
mount -o ro "${partitions[${MOUNT_ROW}, ${DEVICE_INDEX}]}" ${MOUNT_DIR} mount -o ro ${partitions[${MOUNT_ROW},${DEVICE_INDEX}]} ${MOUNT_DIR}
fi fi
CONFIG_DIR=${MOUNT_DIR}boot/ CONFIG_DIR=${MOUNT_DIR}boot/
if [[ "$part_type" == "dos" ]]; then if [[ "$part_type" == "dos" ]]; then
CONFIG_DIR=${MOUNT_DIR} CONFIG_DIR=${MOUNT_DIR}
fi fi
#check VIRTIO #check VIRTIO
HAS_VIRTIO=1 HAS_VIRTIO=1
for conf_file in "${CONFIG_DIR}"config*; do for conf_file in ${CONFIG_DIR}config*; do
out=$(grep -cE "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" "${conf_file}") out=`grep -E "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" ${conf_file} | wc -l`
if [[ "$out" != "2" ]]; then if [[ "$out" != "2" ]]; then
echo "VIRTIO not found" echo "VIRTIO not found"
HAS_VIRTIO=0 HAS_VIRTIO=0
fi fi
done done
#clean up #clean up
umount ${MOUNT_DIR} umount ${MOUNT_DIR}
if [[ "${tmp_created}" == "1" ]]; then if [[ "${tmp_created}" == "1" ]]; then
rm -rf "${working_dir}" rm -rf ${working_dir}
fi fi
if [[ "${image_type}" == "qcow2" ]]; then if [[ "${image_type}" == "qcow2" ]];then
qemu-nbd --disconnect "${dest_file}" >/dev/null qemu-nbd --disconnect ${dest_file} > /dev/null
fi fi
result="" result=""
if [[ "${part_type}" == "dos" ]]; then if [[ "${part_type}" == "dos" ]]; then
result="dos mode not supported" result="dos mode not supported"
fi fi
if [[ "${HAS_VIRTIO}" == "0" ]]; then if [[ "${HAS_VIRTIO}" == "0" ]]; then
if [[ "$result" != "" ]]; then if [[ "$result" != "" ]]; then
result="${result}," result="${result},"
fi fi
result="$result VirtIO module not found in the image" result="$result VirtIO module not found in the image"
fi fi
if [[ "$result" == "" ]]; then if [[ "$result" == "" ]];then
echo "No incompatibilities found" echo "No incompatibilities found"
else else
echo "$result" echo "$result"
fi fi

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