Compare commits

..

397 Commits

Author SHA1 Message Date
Bo Chen
93d7e01b41 build: Release v30.1 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 16:41:05 -07:00
Bo Chen
4fe593e12d tests: Enable live-upgrade tests based on v30.0
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
4203a61947 vmm: Remove unnecessary parentheses (beta 1.69 clippy check)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
e397e739bf tests: Extend '_test_macvtap()' with reboot
In this way, we can cover the scenario where a VM with hotplugged net
device using FDs can work properly with reboot.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
2724edd1e5 vmm: Add valid FDs for TAP devices to 'VmConfig::preserved_fds'
In this way, valid FDs for TAP devices will be closed when the holding
VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
269844da73 vmm: Add unit test for 'VmConfig::preserved_fds'
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
a299a10874 vmm: Implement Clone and Drop for VmConfig
The custom 'clone' duplicates 'preserved_fds' so that the validation
logic can be safely carried out on the clone of the VmConfig.

The custom 'drop' ensures 'preserved_fds' are safely closed when the
holding VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
015941e294 vmm: config: Extend 'VmConfig' with 'preserved_fds'
Preserved FDs are the ones that share the same life-time as its holding
VmConfig instance, such as FDs for creating TAP devices.

Preserved FDs will stay open as long as the holding VmConfig instance is
valid, and will be closed when the holding VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
ca6fe2a98e Revert "vmm: config: Implement Clone for NetConfig"
This reverts commit ea4a95c4f6.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
f4090b0196 Revert "vmm: config: Close FDs for TAP devices that are provided to VM"
This reverts commit b14427540b.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
3432c0ce5e Revert "vmm: config: Don't close reserved FDs from NetConfig::drop()"
This reverts commit 0110fb4edc.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
ec70af1606 Revert "vmm: config: Avoid closing invalid FDs from 'test_net_parsing()'"
This reverts commit 0567def931.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
bb0d82c365 Revert "vmm: config: Replace use of memfd_create with fd pointing to /dev/null"
This reverts commit 46066d6ae1.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Alyssa Ross
2d98a16d05 vmm: only touch the tty flags if it's being used
When neither serial nor console are connected to the tty,
cloud-hypervisor shouldn't touch the tty at all.  One way in which
this is annoying is that if I am running cloud-hypervisor without it
using my terminal, I expect to be able to suspend it with ^Z like any
other process, but that doesn't work if it's put the terminal into raw
mode.

Instead of putting the tty into raw mode when a VM is created or
restored, do it when a serial or console device is created.  Since we
now know it can't be put into raw mode until the Vm object is created,
we can move setting it back to canon mode into the drop handler for
that object, which should always be run in normal operation.  We still
also put the tty into canon mode in the SIGTERM / SIGINT handler, but
check whether the tty was actually used, rather than whether stdin is
a tty.  This requires passing on_tty around as an atomic boolean.

I explored more of an abstraction over the tty — having an object that
encapsulated stdout and put the tty into raw mode when initialized and
into canon mode when dropped — but it wasn't practical, mostly due to
the special requirements of the signal handler.  I also investigated
whether the SIGWINCH listener process could be used here, which I
think would have worked but I'm hesitant to involve it in serial
handling as well as conosle handling.

There's no longer a check for whether the file descriptor is a tty
before setting it into canon mode — it's redundant, because if it's
not a tty it just won't respond to the ioctl.

Tested by shutting down through the API, SIGTERM, and an error
injected after setting raw mode.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
cd1a645421 vmm: don't redundantly set the TTY to canon mode
If the VM is shut down, either it's going to be started again, in
which case we still want to be in raw mode, or the process is about to
exit, in which case canon mode will be set at the end of main.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
4485210de5 vmm: only use KVM_ARM_VCPU_PMU_V3 if available
Having PMU in guests isn't critical, and not all hardware supports
it (e.g. Apple Silicon).

CpuManager::init_pmu already has a fallback for if PMU is not
supported by the VCPU, but we weren't getting that far, because we
would always try to initialise the VCPU with KVM_ARM_VCPU_PMU_V3, and
then bail when it returned with EINVAL.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
0aa858c266 virtio-devices: seccomp: add vhost-user syscalls
Cloud Hypervisor's vhost-user implementation will reconnect if it gets
disconnected from the backend.  That means connections happen inside
the vhost-user seccomp sandbox, so all syscalls used in reconnecting
have to be allowed in that sandbox.

clock_nanosleep is used by Glibc, and nanosleep is used by musl.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Bo Chen
499e8433c3 vmm: Ignore and warn TAP FDs sent via the HTTP request body
Valid FDs can only be sent from another process via `SCM_RIGHTS`.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Omer Faruk Bayram
ff27b00f5a ch-remote: fixed ShutdownVmm and Shutdown commands
Fixed `ShutdownVmm` and `Shutdown` commands to call the correct API
endpoint.

Signed-off-by: Omer Faruk Bayram <omer.faruk@sartura.hr>
2023-04-18 11:47:31 -07:00
Hao Xu
d09af361bc virtio-devices: Reset offset properly upon unmap for virtio-fs.
We should reset the offset to 0, when asked to remove the whole dax
mapping.

Signed-off-by: Hao Xu <howeyxu@tencent.com>
2023-04-18 11:47:31 -07:00
Bo Chen
ece0e6fa92 build: Release v30.0
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-23 16:46:00 -08:00
Bo Chen
2593b67864 misc: Remove tailing whitespaces from release notes and cargo.toml
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-23 16:46:00 -08:00
dependabot[bot]
191e865261 build: Bump once_cell from 1.17.0 to 1.17.1
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.17.0 to 1.17.1.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.17.0...v1.17.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-24 00:36:14 +00:00
dependabot[bot]
ca3a441c49 build: Bump syn from 1.0.107 to 1.0.108 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.107 to 1.0.108.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.107...1.0.108)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-24 00:16:53 +00:00
Wei Liu
de3ca97095 hypervisor: rename get_cpuid to get_supported_cpuid
To better reflect its nature and avoid confusion with get_cpuid2.

No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-02-23 13:03:12 +00:00
Yu Li
74dcb37ec3 vmm: config: fix incorrect values of error
The PR #2333 added I/O rate limiter on block device, with some options
in `DiskConfig`.  And the PR #2401 added rate limiter on virtio-net
device with same options, but it still throws `Error::ParseDisk`.

This commit fixes it with correct values.

Fixes: #2401

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-02-23 09:57:48 +00:00
dependabot[bot]
1d55de9c74 build: Bump virtio-bindings from 0.1.0 to 0.2.0
Bumps [virtio-bindings](https://github.com/rust-vmm/vm-virtio) from 0.1.0 to 0.2.0.
- [Release notes](https://github.com/rust-vmm/vm-virtio/releases)
- [Commits](https://github.com/rust-vmm/vm-virtio/compare/virtio-queue-v0.1.0...virtio-bindings-v0.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-23 00:59:32 +00:00
Ruslan Mstoi
2e94a86b31 scripts: dev_cli.sh: print help if command unspecified
To improve user friendliness, print help text when no command is given.

Signed-off-by: Ruslan Mstoi <ruslan.mstoi@intel.com>
2023-02-22 11:29:54 -08:00
Rob Bradford
996bdc6e08 vfio_user: Use new Rust-VMM crate
This contains the same code as was included in tree.

Fixes: #5123

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-22 15:13:12 +00:00
dependabot[bot]
9d18012c52 build: Bump io-uring from 0.5.12 to 0.5.13 in /fuzz
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.5.12 to 0.5.13.
- [Release notes](https://github.com/tokio-rs/io-uring/releases)
- [Commits](https://github.com/tokio-rs/io-uring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-22 00:18:07 +00:00
dependabot[bot]
6a8bd8e8c5 build: Bump signal-hook-registry from 1.4.0 to 1.4.1
Bumps [signal-hook-registry](https://github.com/vorner/signal-hook) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/vorner/signal-hook/releases)
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.0...registry-v1.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 00:37:30 +00:00
dependabot[bot]
d9184e5256 build: Bump virtio-queue from 0.7.0 to 0.7.1 in /fuzz
Bumps [virtio-queue](https://github.com/rust-vmm/vm-virtio) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/rust-vmm/vm-virtio/releases)
- [Commits](https://github.com/rust-vmm/vm-virtio/compare/virtio-queue-v0.7.0...virtio-queue-v0.7.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 00:21:31 +00:00
dependabot[bot]
5e475e70e6 build: Bump acpi_tables from 4fd38dd to 12bb6d7
Bumps [acpi_tables](https://github.com/rust-vmm/acpi_tables) from `4fd38dd` to `12bb6d7`.
- [Release notes](https://github.com/rust-vmm/acpi_tables/releases)
- [Commits](4fd38dd5f7...12bb6d7b25)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-18 00:37:26 +00:00
Ruslan Mstoi
bd1e1677bd scripts: ch-trace-visualiser.py: remove unused import 'xml'
Unused import 'xml' is redefined at:

> xml = ET.ElementTree(element=svg)

Hence, remove unused xml import.

Signed-off-by: Ruslan Mstoi <ruslan.mstoi@intel.com>
2023-02-17 11:48:37 -08:00
dependabot[bot]
595c9d13a9 build: Bump proc-macro2 from 1.0.50 to 1.0.51
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.50 to 1.0.51.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.50...1.0.51)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-17 05:29:34 +00:00
dependabot[bot]
c2616f3f4f build: Bump signal-hook from 0.3.14 to 0.3.15 in /fuzz
Bumps [signal-hook](https://github.com/vorner/signal-hook) from 0.3.14 to 0.3.15.
- [Release notes](https://github.com/vorner/signal-hook/releases)
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/v0.3.14...v0.3.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-17 00:14:37 +00:00
Rob Bradford
7ceb126184 github: Build examples as well as tests in quality workflow
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
879411e70f build: Ensure pci crate uses vm-memory with required features
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
1181fd21fd vfio_user: Make GPIO device more interesting
Every third read on the GPIO pin will return 1 and also trigger an
interrupt in the guest.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
c8967fcc37 vfio_user: Add command line parsing for socket option
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
19e893fa53 vfio_user: Reject SET_IRQS with VFIO_IRQ_SET_DATA_BOOL
This is unsupported.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
aa502b3e41 vfio_user: Add TODOs for missing functionality
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
10531f052b vfio_user: Always generate an error for commands
Any error from the backend or from the protocol handling code will now
result in an error reply being sent. This is cleanly achieved by
splitting the command handling out into its own method and using the
Rust Result<> based error handling to trigger the generation of the
error reply.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
b072eb454e vfio_user: Add a simple sample device
This implements a similar GPIO device to that found in the libvfio-user
source code.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
b7c2a0f23f vfio_user: Add basic server side support
This allows the implementation of PCI devices in a different process
using the vfio-user protocol.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
874d524a13 vfio_user: Add flags for DMA_UNMAP command
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Rob Bradford
91e2601523 vfio_user: Improve flags for DMA_MAP command
Replace the use of an enum with a bitfield representation which means
that is now possible to logical OR flags together.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-16 09:59:14 -08:00
Yong He
01900e3c2b vmm: properly set vcpu state when thread exited
Once error occur, vcpu thread may exit, this should
be critical event for the whole VM, we should fire
exit event and set vcpu state.

If we don't set vcpu state, the shutdown process
will hang at signal_thread, which is waiting the
vcpu state to change.

Signed-off-by: Yong He <alexyonghe@tencent.com>
2023-02-16 14:40:04 +00:00
dependabot[bot]
e35ef40029 build: Bump fdt from 0.1.4 to 0.1.5
Bumps [fdt](https://github.com/repnop/fdt) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/repnop/fdt/releases)
- [Commits](https://github.com/repnop/fdt/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-16 00:36:48 +00:00
dependabot[bot]
aa0af5f8d7 build: Bump proc-macro2 from 1.0.50 to 1.0.51 in /fuzz
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.50 to 1.0.51.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.50...1.0.51)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-16 00:14:39 +00:00
Rob Bradford
46066d6ae1 vmm: config: Replace use of memfd_create with fd pointing to /dev/null
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-15 11:10:00 -08:00
Rob Bradford
51c1738d55 tests: Disable test_vfio test
This test (which relies on nesting) is failing on the VFIO worker. The tests that use the
dedicated hardware pass fine.

See: #5190

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-15 12:30:34 +00:00
Bo Chen
0567def931 vmm: config: Avoid closing invalid FDs from 'test_net_parsing()'
We need to provide valid FDs while creating 'NetConfig' instances even
for unit tests. Closing invalid FDs would cause random unit test
failures.

Also, two identical 'NetConfig' instances are not allowed any more,
because it would lead to close the same FD twice. This is consistent
with the fact that a clone of a "NetConfig" instance is no
longer *equal* to the instance itself.

Fixes: #5203

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-15 12:30:09 +00:00
Bo Chen
0110fb4edc vmm: config: Don't close reserved FDs from NetConfig::drop()
Fixes: #5203

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-15 12:30:09 +00:00
dependabot[bot]
4f945743cb build: Bump is-terminal from 0.4.2 to 0.4.3
Bumps [is-terminal](https://github.com/sunfishcode/is-terminal) from 0.4.2 to 0.4.3.
- [Release notes](https://github.com/sunfishcode/is-terminal/releases)
- [Commits](https://github.com/sunfishcode/is-terminal/compare/v0.4.2...v0.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-15 11:27:27 +00:00
dependabot[bot]
8f6afec520 build: Bump once_cell from 1.17.0 to 1.17.1 in /fuzz
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.17.0 to 1.17.1.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.17.0...v1.17.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-15 00:14:51 +00:00
Rob Bradford
b14427540b vmm: config: Close FDs for TAP devices that are provided to VM
These are owned by the config (and are duplicated before being used to
create the `Tap` for the virtio-net device.)

By implementing Drop on NetConfig we have issues with moving out of
members that don't implement the Copy trait. This requires a small
adjustment to the unit tests that use the Default::default() function.

Fixes: #5197

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-14 12:37:50 +01:00
Rob Bradford
ea4a95c4f6 vmm: config: Implement Clone for NetConfig
The custom version duplicates any FDs that have been provided so that
the validation logic used on hotplug, which takes a clone of the config,
can be safely carried out.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-14 12:37:50 +01:00
dependabot[bot]
f5084f7c65 build: Bump uuid from 1.2.2 to 1.3.0
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.2.2...1.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-14 00:37:27 +00:00
dependabot[bot]
45ab9f77b7 build: Bump signal-hook-registry from 1.4.0 to 1.4.1 in /fuzz
Bumps [signal-hook-registry](https://github.com/vorner/signal-hook) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/vorner/signal-hook/releases)
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.0...registry-v1.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-14 00:24:21 +00:00
dependabot[bot]
f0ea8eb70b build: Bump serde_json from 1.0.91 to 1.0.93
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.91 to 1.0.93.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.91...v1.0.93)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 14:09:46 +01:00
Bo Chen
3377e0e983 docs: hotplug: Fix link to booting with uefi on aarch64
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-12 14:40:04 +08:00
dependabot[bot]
e9435b1327 build: Bump serde_json from 1.0.92 to 1.0.93 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.92 to 1.0.93.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.92...v1.0.93)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-11 00:17:12 +00:00
Rob Bradford
09fca4a5dd build: Move to rust-vmm acpi_tables crate
This code is indentical to what is in this repository. When a release
gets made we can then switch to that.

Fixes: #5122

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-10 18:58:12 +01:00
Praveen K Paladugu
1143d54ee0 tpm: Add recv timeout while running recvmsg
If swtpm becomes unresponsive, guest gets blocked at "recvmsg" on tpm's
data FD. This change adds a timeout to the data fd socket. If swtpm
becomes unresponsive guest waits for "timeout" (secs) and continues to
run after returning an I/O error to tpm commands.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2023-02-10 17:49:03 +01:00
Anatol Belski
934b20a77a ci: Switch to Windows Server 2022
The updated image is configured in a same way as the previously used
2019, it has same

- Credentials
- Services configured, like SAC, SSH, RDP
- Size

All the Windows updates are applied so the state is current to the date.
Also, the latest stable version 0.1.229 of the VirtIO Windows drivers
is installed.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2023-02-10 17:48:46 +01:00
Jinank Jain
b54ce6c3db vmm: Defer address space allocation
We can ideally defer the address space allocation till we start the
vCPUs for the very first time. Because the VM will not access the memory
until the CPUs start running. Thus there is no need to allocate the
address space eagerly and wait till the time we are going to start the
vCPUs for the first time.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2023-02-10 11:52:20 +01:00
Kaihang Zhang
3dd01443d5 openapi: Make 'vcpu' and 'host_cpus' required in CpuAffinity
Signed-off-by: Kaihang Zhang <kaihang.zhang@smartx.com>
2023-02-10 10:06:43 +01:00
dependabot[bot]
43227cd5c4 build: Bump anyhow from 1.0.68 to 1.0.69
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.68 to 1.0.69.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.68...1.0.69)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-10 00:55:05 +00:00
dependabot[bot]
176e438d17 build: Bump anyhow from 1.0.68 to 1.0.69 in /fuzz
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.68 to 1.0.69.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.68...1.0.69)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-10 00:13:38 +00:00
Rob Bradford
c22c4675b3 arch, hypervisor: Populate CPUID leaf 0x4000_0010 (TSC frequency)
This hypervisor leaf includes details of the TSC frequency if that is
available from KVM. This can be used to efficiently calculate time
passed when there is an invariant TSC.

TEST=Run `cpuid` in the guest and observe the frequency populated.

Fixes: #5178

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-09 18:32:21 +01:00
Rob Bradford
7ccf58a019 Revert "build: Temporarily disable bare metal x86-64 workers"
This reverts commit 496f932276.

The systems are back online and reachable.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-09 16:30:07 +01:00
dependabot[bot]
48e1af7d3c build: Bump fdt from 0.1.4 to 0.1.5 in /fuzz
Bumps [fdt](https://github.com/repnop/fdt) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/repnop/fdt/releases)
- [Commits](https://github.com/repnop/fdt/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-08 23:20:11 +00:00
dependabot[bot]
341a69c39c build: Bump openssl-src from 111.24.0+1.1.1s to 111.25.0+1.1.1t
Bumps [openssl-src](https://github.com/alexcrichton/openssl-src-rs) from 111.24.0+1.1.1s to 111.25.0+1.1.1t.
- [Release notes](https://github.com/alexcrichton/openssl-src-rs/releases)
- [Commits](https://github.com/alexcrichton/openssl-src-rs/commits)

---
updated-dependencies:
- dependency-name: openssl-src
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-08 23:09:51 +00:00
dependabot[bot]
5d34d85b92 build: Bump darling from 0.14.2 to 0.14.3
Bumps [darling](https://github.com/TedDriggs/darling) from 0.14.2 to 0.14.3.
- [Release notes](https://github.com/TedDriggs/darling/releases)
- [Changelog](https://github.com/TedDriggs/darling/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TedDriggs/darling/compare/v0.14.2...v0.14.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-07 23:40:55 +00:00
dependabot[bot]
bcd46906ec build: Bump serde_json from 1.0.91 to 1.0.92 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.91 to 1.0.92.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.91...v1.0.92)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-07 23:17:44 +00:00
Bo Chen
bc59ca72f3 docs: Update the intel_tdx documentation
Updates include:
- Add references to 'TDX Tools'
- Expand instructions on buidling and using TDShim
- Add version information of guest/host kernel, TDVF, TDShim being tested

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-07 06:30:38 -08:00
dependabot[bot]
995945dd25 build: Bump rustix from 0.36.7 to 0.36.8
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.36.7 to 0.36.8.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.36.7...v0.36.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 23:42:06 +00:00
dependabot[bot]
8edd81ec82 build: Bump darling from 0.14.2 to 0.14.3 in /fuzz
Bumps [darling](https://github.com/TedDriggs/darling) from 0.14.2 to 0.14.3.
- [Release notes](https://github.com/TedDriggs/darling/releases)
- [Changelog](https://github.com/TedDriggs/darling/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TedDriggs/darling/compare/v0.14.2...v0.14.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 23:21:38 +00:00
dependabot[bot]
726cfa41f4 build: Bump pnet and pnet_datalink from 0.31.0 to 0.33.0
Bumps [pnet](https://github.com/libpnet/libpnet) from 0.31.0 to 0.33.0.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.31.0...v0.33.0)

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

Signed-off-by: Bo Chen <chen.bo@intel.com>
Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 19:26:36 +00:00
dependabot[bot]
d19a5d5356 build: Bump mshv-bindings from 48b389a to 0b2af25
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `48b389a` to `0b2af25`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](48b389af1f...0b2af25128)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 23:42:08 +00:00
Rob Bradford
69e8f60b91 tdx: Set the SEPT_VE_DISABLE attribute
This is required for booting Linux:

From: https://lore.kernel.org/all/20221028141220.29217-3-kirill.shutemov@linux.intel.com/

"""

Virtualization Exceptions (#VE) are delivered to TDX guests due to
specific guest actions such as using specific instructions or accessing
a specific MSR.

Notable reason for #VE is access to specific guest physical addresses.
It requires special security considerations as it is not fully in
control of the guest kernel. VMM can remove a page from EPT page table
and trigger #VE on access.

The primary use-case for #VE on a memory access is MMIO: VMM removes
page from EPT to trigger exception in the guest which allows guest to
emulate MMIO with hypercalls.

MMIO only happens on shared memory. All conventional kernel memory is
private. This includes everything from kernel stacks to kernel text.

Handling exceptions on arbitrary accesses to kernel memory is
essentially impossible as handling #VE may require access to memory
that also triggers the exception.

TDX module provides mechanism to disable #VE delivery on access to
private memory. If SEPT_VE_DISABLE TD attribute is set, private EPT
violation will not be reflected to the guest as #VE, but will trigger
exit to VMM.

Make sure the attribute is set by VMM. Panic otherwise.

There's small window during the boot before the check where kernel has
early #VE handler. But the handler is only for port I/O and panic as
soon as it sees any other #VE reason.

SEPT_VE_DISABLE makes SEPT violation unrecoverable and terminating the
TD is the only option.

Kernel has no legitimate use-cases for #VE on private memory. It is
either a guest kernel bug (like access of unaccepted memory) or
malicious/buggy VMM that removes guest page that is still in use.

In both cases terminating TD is the right thing to do.

"""

With this change Cloud Hypervisor can boot the current Linux guest
kernel.

Reported-By: Jiaqi Gao <jiaqi.gao@intel.com
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-02 14:53:59 +00:00
dependabot[bot]
c6eb69caba build: Bump miniz_oxide from 0.6.2 to 0.6.4
Bumps [miniz_oxide](https://github.com/Frommi/miniz_oxide) from 0.6.2 to 0.6.4.
- [Release notes](https://github.com/Frommi/miniz_oxide/releases)
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/compare/0.6.2...0.6.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 23:44:16 +00:00
dependabot[bot]
e4ed9bc557 build: Bump uuid from 1.2.2 to 1.3.0 in /fuzz
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.2.2...1.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 23:27:32 +00:00
dependabot[bot]
f4509c3611 build: Bump kvm-ioctls from 0.12.0 to 0.13.0
Bumps [kvm-ioctls](https://github.com/rust-vmm/kvm-ioctls) from 0.12.0 to 0.13.0.
- [Release notes](https://github.com/rust-vmm/kvm-ioctls/releases)
- [Changelog](https://github.com/rust-vmm/kvm-ioctls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-vmm/kvm-ioctls/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-02-01 12:23:00 +00:00
Bo Chen
ecbb8ab282 docs: Add @likebreath to MAINTAINERS.md
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-02-01 12:19:07 +00:00
Wei Liu
29ebecccb0 tpm: be more consistent when converting responses
Do the following:

1. Use from_be_bytes to drop mutable slices.
2. Check for the exact buffer size throughout.
3. Simplify ptm_to_request where possible.
4. Make error messages style consistent.

Fix a typo in code comment while at it.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-31 18:09:28 +00:00
Wei Liu
5646a917ff tpm: handle short write
There is no guarantee that the write can send the whole buffer at once.

In those rare occasions, we should return a sensible error.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-31 18:09:28 +00:00
Wei Liu
6e22f23831 tpm: save almost 8KB stack space
The largest possible PTM response is only 16 bytes. Size the output
buffer correctly.

In the socket read function, rely on the caller to provide a
sufficiently large buffer. That eliminates another large stack variable.

In total this saves almost 8KB stack space.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-31 18:09:28 +00:00
Wei Liu
8e996ff2fe tpm: drop unnecessary cast
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-31 18:09:28 +00:00
Wei Liu
2d2f356d94 devices: tpm: failure to deliver request is considered fatal
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-31 18:09:18 +00:00
dependabot[bot]
938c16f2b2 build: Bump cc from 1.0.78 to 1.0.79
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.78 to 1.0.79.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.78...1.0.79)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-31 13:51:07 +00:00
dependabot[bot]
105a7dd7aa build: Bump cc from 1.0.78 to 1.0.79 in /fuzz
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.78 to 1.0.79.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.78...1.0.79)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 23:21:59 +00:00
Wei Liu
11ef495e6b performance-metrics: share build.rs from project root
No need to duplicate the same content in two places.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-30 21:10:02 +00:00
Wei Liu
34b3170680 vmm: fix two typos
Change "thead" to "thread".

Also make sure the two messages are distinguishable by adding "vmm" and
"vm" prefix.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-30 21:10:02 +00:00
Wei Liu
427a2bacf5 block_util: convert aligned_operations to SmallVec
The number of aligned operations can not be larger than the number of
descriptors. Initializing the capacity to 1 is good enough per the
observation that most of time there is only one data descriptor in a
given request.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-30 08:13:40 +00:00
Wei Liu
1325c76525 block_util: use SmallVec in async adaptor
Also fix a comment while at it.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-30 08:13:40 +00:00
Michael Zhao
4a51a6615f arch: Fix AArch64 socket setting in CPU topology
Before Linux v6.0, AArch64 didn't support "socket" in "cpu-map"
(CPU topology) of FDT.

We found that clusters can be used in the same way of sockets. That is
the way we implemented the socket settings in Cloud Hypervisor. But in
fact it was a bug.

Linux commit 26a2b7 fixed the mistake. So the cluster nodes can no
longer act as sockets. And in a following commit dea8c0, sockets were
supported.

This patch fixed the way to configure sockets. In each socket, a default
cluster was added to contain all the cores, because cluster layer is
mandatory in CPU topology on AArch64.

This fix will break the socket settings on the guests where the kernel
version is lower than v6.0. In that case, if socket number is set to
more than 1, the kernel will treat that as FDT mistake and all the CPUs
will be put in single cluster of single socket.

The patch only impacts the case of using FDT, not ACPI.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2023-01-30 08:12:56 +00:00
Rob Bradford
d5ce855649 misc: Update reference kernel to 6.1.6
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-30 08:12:56 +00:00
Bo Chen
496f932276 build: Temporarily disable bare metal x86-64 workers
These machines are unreachable.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-01-28 09:27:27 +00:00
dependabot[bot]
c33efe294a build: Bump micro_http from fbef706 to b538bf8
Bumps [micro_http](https://github.com/firecracker-microvm/micro-http) from `fbef706` to `b538bf8`.
- [Release notes](https://github.com/firecracker-microvm/micro-http/releases)
- [Commits](fbef706e28...b538bf89e5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-27 23:59:35 +00:00
dependabot[bot]
2d022d0c85 build: Bump micro_http from fbef706 to b538bf8 in /fuzz
Bumps [micro_http](https://github.com/firecracker-microvm/micro-http) from `fbef706` to `b538bf8`.
- [Release notes](https://github.com/firecracker-microvm/micro-http/releases)
- [Commits](fbef706e28...b538bf89e5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-27 23:19:16 +00:00
Praveen K Paladugu
5b31b19530 tests: enable tpm tests for mshv
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2023-01-27 21:14:38 +00:00
Praveen K Paladugu
ad202f9b7a hypervisor: x86: emulate MOVSB
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2023-01-27 21:14:38 +00:00
Wei Liu
3a225aaa23 hypervisor: x86: emulate MOVSW
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-27 21:14:38 +00:00
Wei Liu
1bfa07f48e hypervisor: x86: use a macro to generate emulate function for movs
No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-27 21:14:38 +00:00
Ravi kumar Veeramally
8e682bcb00 scripts: Avoid warning from mkdosfs command
Fix lowercase label to avoid "mkfs.fat: Warning: lowercase labels
might not work properly on some systems".

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
2023-01-27 08:12:38 -08:00
Bo Chen
1ee2922dbc Jenkinsfile: Enforce global execution timeout
This patch adds a global execution timeout to the Jenkinsfile to avoid
infinite pending Jenkins pipelines, such as when certain worker nodes
are not available. The global execution timeout is now set to 4 hours
which is derived from total timeout of our longest stage (e.g. the
`Worker build`).

Fixes: #5148

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-01-27 08:04:40 +00:00
dependabot[bot]
2ce503f457 build: Bump libfuzzer-sys from 0.4.5 to 0.4.6 in /fuzz
Bumps [libfuzzer-sys](https://github.com/rust-fuzz/libfuzzer) from 0.4.5 to 0.4.6.
- [Release notes](https://github.com/rust-fuzz/libfuzzer/releases)
- [Changelog](https://github.com/rust-fuzz/libfuzzer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/libfuzzer/compare/0.4.5...0.4.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-26 23:17:41 +00:00
Bo Chen
574576c8e9 misc: Automatically fix cargo clippy issues added in 1.68 (beta)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-01-26 08:58:37 -08:00
Ravi kumar Veeramally
aaf67c9ae4 doc: Add musl-tools to instructions for build
As a first time user of cloud-hypervisor and Rust environment
you get build errors with out this.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
2023-01-26 08:09:46 -08:00
Rob Bradford
8b9da4e286 build: Bump MSRV to 1.62
Needed for #[derive(Default)] on enums which is now clippy checked in
1.68.

Fixes: #5140

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-26 13:05:23 +00:00
dependabot[bot]
271f11d9ec build: Bump ssh2 from 0.9.3 to 0.9.4
Bumps [ssh2](https://github.com/alexcrichton/ssh2-rs) from 0.9.3 to 0.9.4.
- [Release notes](https://github.com/alexcrichton/ssh2-rs/releases)
- [Commits](https://github.com/alexcrichton/ssh2-rs/compare/0.9.3...0.9.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-26 07:59:11 +00:00
Muminul Islam
e436b382cc scripts: check if /dev/{mshv,kvm} exists before test run
Right now integration test fails during the test run if
/dev/mshv or /dev/kvm does not exist. We should not
progress and exit early if not present.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2023-01-26 07:58:13 +00:00
Wei Liu
1ce1fe7334 tpm: rework set_buffer_size
Make the code more idiomatic by wrapping the actual size configured in
the returning Result type. This further allows simplifying
get_buffer_size.

The debug message in startup_tpm is more useful if it prints out the
actual size than the wanted size.

No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
73af65f417 tpm: drop unused fields in BackendCmd struct
They are never used.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
cffde0ff65 devices: avoid unnecessary allocations in TPM code
Use the data buffer in the TPM device directly.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
e41b7d90d5 tpm: drop cmd from Emulator struct
The command is not done asynchronously. And there is no way to propagate
this error anywhere.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
60425471dd tpm: get_buffer_size always succeeds
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
2b76e1d7ba devices: simplify TPM handling
The error is never propagated anywhere. Drop it.

Avoid unwrapping unconditionally.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
15ace525be devices: drop cmd field from TPM struct
There is no need to hold on to it. It is only used locally in a
function.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-26 07:57:48 +00:00
Wei Liu
8db630763a devices: clean up two comments in TPM code
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-25 18:40:57 +00:00
Wei Liu
cd1470e289 devices: rework TPM register and field look-up
Match against enums instead.

This then drops the need to import phf.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-25 18:40:57 +00:00
Wei Liu
99d8c34861 devices: change TPM_CRB_R_MAX from u32 to usize
This simplifies the code a bit.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-25 18:40:57 +00:00
Philipp Schuster
6725771dc3 virtio-devices: typo fixes
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2023-01-25 10:38:31 +00:00
dependabot[bot]
0e8fd0bc17 build: Bump object from 0.30.2 to 0.30.3
Bumps [object](https://github.com/gimli-rs/object) from 0.30.2 to 0.30.3.
- [Release notes](https://github.com/gimli-rs/object/releases)
- [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.30.2...0.30.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-24 23:41:13 +00:00
dependabot[bot]
0ef1e668a5 build: Bump quote from 1.0.21 to 1.0.23 in /fuzz
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.21 to 1.0.23.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.21...1.0.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-24 23:21:28 +00:00
dependabot[bot]
477332a94a build: Bump arbitrary from 1.2.0 to 1.2.3 in /fuzz
Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.2.0 to 1.2.3.
- [Release notes](https://github.com/rust-fuzz/arbitrary/releases)
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.2.0...v1.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-24 00:26:33 +00:00
dependabot[bot]
7b102c4fa3 build: Bump gimli from 0.27.0 to 0.27.1
Bumps [gimli](https://github.com/gimli-rs/gimli) from 0.27.0 to 0.27.1.
- [Release notes](https://github.com/gimli-rs/gimli/releases)
- [Changelog](https://github.com/gimli-rs/gimli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/gimli/compare/0.27.0...0.27.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-23 23:43:21 +00:00
Praveen K Paladugu
1e159dbefb tests: Add a test for tpm driver
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2023-01-23 10:10:19 -08:00
Praveen K Paladugu
a4ef6e57a7 ci: install swtpm in Docker container
Add steps to build and install swtpm and its dependencies in
ci docker container.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
2023-01-23 10:10:19 -08:00
Bo Chen
ec45daac19 docs: Use the TDVF firmware from the edk2 repository
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-01-23 10:25:27 +01:00
dependabot[bot]
c773330a65 build: Bump arc-swap from 1.5.1 to 1.6.0 in /fuzz
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/vorner/arc-swap/releases)
- [Changelog](https://github.com/vorner/arc-swap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/arc-swap/compare/v1.5.1...v1.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-20 23:17:10 +00:00
Sebastien Boeuf
e4ae668bcd tdx: Update support based on kvm-upstream v5.19
In order to comply with latest TDX version, we rely onto the branch
kvm-upstream-2022.08.07-v5.19-rc8 from https://github.com/intel/tdx
repository. Updates are based on changes that happened in
arch/x86/include/uapi/asm/kvm.h headers file.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2023-01-20 09:59:56 +00:00
Rob Bradford
f6c058da56 .github: Don't try and create releases for created branches
Dependabot will create a branch on the repo for it's updates this
triggers the release action (because it's the same event as a tag) which
will then fail leading to dependabot PRs not being automerged. Instead
only run the release check test on PRs or tag creation.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-20 09:58:53 +00:00
dependabot[bot]
089dffcb49 build: Bump io-uring from 0.5.11 to 0.5.12
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.5.11 to 0.5.12.
- [Release notes](https://github.com/tokio-rs/io-uring/releases)
- [Commits](https://github.com/tokio-rs/io-uring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-20 09:24:06 +00:00
dependabot[bot]
9d7034b9c6 build: Bump io-uring from 0.5.11 to 0.5.12 in /fuzz
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.5.11 to 0.5.12.
- [Release notes](https://github.com/tokio-rs/io-uring/releases)
- [Commits](https://github.com/tokio-rs/io-uring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-20 09:44:48 +01:00
Rob Bradford
a86edd3032 tests: Add tpm2-tools to custom jammy image
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-19 19:19:52 +00:00
Anirudh Rayabharam
7805fe58e2 tests: disable test_memory_mergeable_on for mshv
KSM doesn't work with MSHV stack since guest memory is pinned
(`pin_user_pages`) and pinned pages cannot be merged.

So, don't run the test for mshv.

Signed-off-by: Anirudh Rayabharam <anrayabh@linux.microsoft.com>
2023-01-19 13:25:40 +00:00
dependabot[bot]
e66ffffd43 build: Bump rustix from 0.36.6 to 0.36.7
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.36.6 to 0.36.7.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.36.6...v0.36.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-19 07:36:35 +00:00
dependabot[bot]
843c8ad51c build: Bump proc-macro2 from 1.0.49 to 1.0.50 in /fuzz
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.49 to 1.0.50.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.49...1.0.50)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-19 07:36:23 +00:00
dependabot[bot]
a334831d54 build: Bump vmm-sys-util from 0.11.0 to 0.11.1 in /fuzz
Bumps [vmm-sys-util](https://github.com/rust-vmm/vmm-sys-util) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/rust-vmm/vmm-sys-util/releases)
- [Changelog](https://github.com/rust-vmm/vmm-sys-util/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-vmm/vmm-sys-util/compare/v0.11.0...v0.11.1)

---
updated-dependencies:
- dependency-name: vmm-sys-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-18 11:30:04 +00:00
Rob Bradford
dab9f1cf30 docs: Add instructions for heap profiling
Fixes: #5074

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-17 14:02:01 +00:00
Rob Bradford
3a81f9328f build: Add optional dhat heap profiling
Add new "dhat-heap" build feature which enables dhat heap profiling.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-17 14:02:01 +00:00
Rob Bradford
e2886a4b1f docs: Update instructions to point to new profiling target
This removes the need for the user to manually change the Cargo.toml
file for profiling.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-17 14:02:01 +00:00
Rob Bradford
c6d3f61a42 build: Add new profiling target
This makes it much more convenient to build binaries for profiling
without having to modify the Cargo.toml file.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-17 14:02:01 +00:00
dependabot[bot]
4689abd9f4 build: Bump argh_derive from 0.1.9 to 0.1.10
Bumps [argh_derive](https://github.com/google/argh) from 0.1.9 to 0.1.10.
- [Release notes](https://github.com/google/argh/releases)
- [Commits](https://github.com/google/argh/compare/0.1.9...0.1.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-17 09:11:48 +01:00
dependabot[bot]
f479f0605d build: Bump serde_with from 2.1.0 to 2.2.0 in /fuzz
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v2.1.0...v2.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-17 09:11:36 +01:00
Rob Bradford
5034bea8c4 Docker: Update Rust toolchain in dev container
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-16 16:43:49 +00:00
Wei Liu
b8172408f8 vhost_user_net: add --version
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
b0a2ce0598 vhost_user_block: add --version
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
a0922930b1 docs: update command line options
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
d1ec65873e vhost_user_net: switch to argh
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
54e9ed9932 vhost_user_blk: switch to argh
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
111225a2a5 main: switch to argh
A few breaking changes:

1. `-vvv` needs to be written as `-v -v -v`.
2. `--disk D1 D2` and others need to be written as `--disk D1 --disk D2`.
3. `--option=value` needs to be written as `--option value`

Change integration tests to adapt to the breaking changes.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
fe49056129 main: split out a few functions
Switching to `argh` requires individual default functions.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
d5558aea2a ch-remote: switch to argh
Since argh does not support `--option=value`, we need to change the
integration test code to become `--option value`.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
Wei Liu
1ba995d952 performance-metrics: switch to argh
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-16 16:39:03 +00:00
dependabot[bot]
c6c081099f build: Bump proc-macro2 from 1.0.47 to 1.0.49
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.47 to 1.0.49.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.47...1.0.49)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-16 09:22:06 +01:00
dependabot[bot]
3a1254a9b2 build: Bump clap from 4.0.32 to 4.1.0 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.32 to 4.1.0.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.32...clap_complete-v4.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-16 09:21:57 +01:00
Rob Bradford
6e9172bf6f .github: Re-order release steps to ensure binaries are available
Since we run "cargo clean" before running the aarch64 build we need to
create the release and upload the x86-64 assets before the clean.

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-13 01:34:59 +00:00
dependabot[bot]
0e273e8b0d build: Bump once_cell from 1.16.0 to 1.17.0 in /fuzz
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.16.0...v1.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-13 00:34:13 +00:00
Philipp Schuster
ad6c0ee52b virtio-devices: properly join all threads on Drop
This change is important to do a proper resource cleanup. We decided
to do this repetitive approach as VirtioCommon can't implement Drop
without major changes to the corresponding code. Also, devices such as
Net can't easily use the epoll_threads-abstraction from VirtioCommon as
it has multiple threads with different semantics.

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

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

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

Fixes: #4792.

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

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

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

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

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

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

The average latency is calculated based on cumulative average.

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

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

Fixes #5037

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

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

Or under Azure:

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

Fixes: #5067

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

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

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

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

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

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

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

Before:

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

After:

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

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

DHAT reports:

Before:

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

After:

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

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

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

See: #5082

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

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

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

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

A user was identified of this functionality.

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

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

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

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

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

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

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

 to

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

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

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

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

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

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2023-01-09 15:16:48 +00:00
dependabot[bot]
67340c5295 build: Bump clap from 4.0.29 to 4.0.32
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.29 to 4.0.32.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.29...v4.0.32)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 02:10:58 +00:00
dependabot[bot]
6eb0330bed build: Bump clap from 4.0.29 to 4.0.32 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.29 to 4.0.32.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.29...v4.0.32)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

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

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

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

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

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

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

See: #5014

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

See: #4837

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

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

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

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

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

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

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

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

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

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

The table is composed of structures with the form:

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes: #4964

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

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

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

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

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

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

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

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

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

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

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

See: #4761

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 23:46:48 +00:00
dependabot[bot]
105c6cfc5a build: Bump clap from 4.0.27 to 4.0.29 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.27 to 4.0.29.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.27...v4.0.29)

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

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

Fixes: #4318

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

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

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

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

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

Signed-off-by: Yuji Hagiwara <yuuzi41@gmail.com>
2022-11-27 18:55:07 +00:00
dependabot[bot]
1fd5384062 build: Bump regex-syntax from 0.6.27 to 0.6.28
Bumps [regex-syntax](https://github.com/rust-lang/regex) from 0.6.27 to 0.6.28.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/commits)

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

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

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

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

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

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

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 08:55:14 +00:00
dependabot[bot]
6a29eba69e build: Bump regex from 1.6.0 to 1.7.0
Bumps [regex](https://github.com/rust-lang/regex) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.6.0...1.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-24 23:44:40 +00:00
dependabot[bot]
98e10062e8 build: Bump clap from 4.0.26 to 4.0.27 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.26 to 4.0.27.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.26...v4.0.27)

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

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

Fixes: #4915

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

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

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

Fixes: #4915

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes: #4918

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-19 00:27:00 +00:00
dependabot[bot]
cee2d6627d build: Bump clap from 4.0.18 to 4.0.26 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.18 to 4.0.26.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.18...v4.0.26)

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
dependabot[bot]
cd24f470f4 build: Bump getrandom from 0.2.7 to 0.2.8
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.7 to 0.2.8.
- [Release notes](https://github.com/rust-random/getrandom/releases)
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.2.7...v0.2.8)

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

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

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

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

View File

@@ -13,7 +13,7 @@ jobs:
- stable
- beta
- nightly
- "1.65"
- "1.62"
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
@@ -34,22 +34,22 @@ jobs:
override: true
- name: Build (default features)
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (default features + tdx)
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (default features + guest_debug)
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (mshv)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (mshv + kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Release Build (default features)
run: cargo build --locked --all --release --target=${{ matrix.target }}

View File

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

View File

@@ -16,29 +16,29 @@ jobs:
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.65"
toolchain: "1.62"
target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.65"
toolchain: "1.62"
target: x86_64-unknown-linux-musl
- name: Build
uses: actions-rs/cargo@v1
with:
toolchain: "1.65"
command: build
args: --all --release --target=x86_64-unknown-linux-gnu
toolchain: "1.62"
command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu
- name: Static Build
uses: actions-rs/cargo@v1
with:
toolchain: "1.65"
command: build
args: --all --release --target=x86_64-unknown-linux-musl
toolchain: "1.62"
command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.65"
toolchain: "1.62"
target: aarch64-unknown-linux-musl
override: true
- name: Create Release

1
.gitignore vendored
View File

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

654
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "cloud-hypervisor"
version = "28.4.0"
version = "30.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
default-run = "cloud-hypervisor"
@@ -12,10 +12,10 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
# Can only be bumped by:
# a.) A dependency requires it,
# a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.65"
rust-version = "1.62"
[profile.release]
lto = true
@@ -23,29 +23,32 @@ codegen-units = 1
opt-level = "s"
strip = true
[profile.profiling]
inherits = "release"
strip = false
debug = true
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.69"
api_client = { path = "api_client" }
clap = { version = "4.0.29", features = ["wrap_help","cargo","string"] }
argh = "0.1.9"
dhat = { version = "0.3.2", optional = true }
epoll = "4.3.1"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = "0.2.138"
libc = "0.2.139"
log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = "0.3.0"
serde_json = "1.0.89"
serde_json = "1.0.93"
signal-hook = "0.3.14"
thiserror = "1.0.37"
thiserror = "1.0.38"
tpm = { path = "tpm"}
tracer = { path = "tracer" }
vmm = { path = "vmm" }
vmm-sys-util = "0.11.0"
vm-memory = "0.10.0"
[build-dependencies]
clap = { version = "4.0.29", features = ["cargo"] }
# List of patched crates
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
@@ -55,13 +58,14 @@ versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_deri
[dev-dependencies]
dirs = "4.0.0"
net_util = { path = "net_util" }
once_cell = "1.16.0"
serde_json = "1.0.89"
once_cell = "1.17.1"
serde_json = "1.0.93"
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"
[features]
default = ["kvm"]
dhat-heap = ["dhat"] # For heap profiling
guest_debug = ["vmm/guest_debug"]
kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"]
@@ -70,7 +74,6 @@ tracing = ["vmm/tracing", "tracer/tracing"]
[workspace]
members = [
"acpi_tables",
"api_client",
"arch",
"block_util",
@@ -87,7 +90,6 @@ members = [
"serial_buffer",
"test_infra",
"tracer",
"vfio_user",
"vhdx",
"vhost_user_block",
"vhost_user_net",

158
Jenkinsfile vendored
View File

@@ -1,6 +1,9 @@
def runWorkers = true
pipeline {
agent none
options {
timeout(time: 4, unit: 'HOURS')
}
stages {
stage('Early checks') {
agent { node { label 'built-in' } }
@@ -10,29 +13,16 @@ pipeline {
checkout scm
}
}
stage('Check for documentation only changes') {
stage('Check if worker build can be skipped') {
when {
expression {
return docsFileOnly()
return skipWorkerBuild()
}
}
steps {
script {
runWorkers = false
echo 'Documentation only changes, no need to run the CI'
}
}
}
stage('Check for fuzzer files only changes') {
when {
expression {
return fuzzFileOnly()
}
}
steps {
script {
runWorkers = false
echo 'Fuzzer cargo files only changes, no need to run the CI'
echo 'No changes requring a build'
}
}
}
@@ -227,7 +217,7 @@ pipeline {
stage('Download assets') {
steps {
sh "mkdir ${env.HOME}/workloads"
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2022-amd64-2.raw" --name windows-server-2022-amd64-2.raw --connection-string "$AZURE_CONNECTION_STRING"'
}
}
stage('Run Windows guest integration tests') {
@@ -281,6 +271,113 @@ pipeline {
}
}
}
stage('Worker build - Rate Limiter') {
agent { node { label 'focal-metrics' } }
when {
branch 'main'
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run rate-limiter integration tests') {
options {
timeout(time: 10, unit: 'MINUTES')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-rate-limiter'
}
}
}
}
stage('Worker build - SGX') {
agent { node { label 'jammy-sgx' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run SGX integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx'
}
}
stage('Run SGX integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
stage('Worker build - VFIO') {
agent { node { label 'jammy-vfio' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run VFIO integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-vfio'
}
}
stage('Run VFIO integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-vfio --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
}
}
}
@@ -325,24 +422,31 @@ def installAzureCli(distro, arch) {
sh 'sudo apt install -y azure-cli'
}
def boolean docsFileOnly() {
def boolean skipWorkerBuild() {
if (env.CHANGE_TARGET == null) {
return false
}
return sh(
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
) != 0
}
def boolean fuzzFileOnly() {
if (env.CHANGE_TARGET == null) {
return false
) != 0) {
return true
}
return sh(
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz/'"
) != 0
) != 0) {
return true
}
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E '.github/'"
) != 0) {
return true
}
return false
}

View File

@@ -2,6 +2,7 @@
- Sebastien Boeuf - @sboeuf
- Robert Bradford - @rbradford
- Bo Chen - @likebreath
- Samuel Ortiz - @sameo
- Wei Liu - @liuw
- Michael Zhao - @michael2012z

View File

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

View File

@@ -1,8 +0,0 @@
[package]
name = "acpi_tables"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
vm-memory = "0.10.0"

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
pub mod aml;
pub mod rsdp;
pub mod sdt;
fn generate_checksum(data: &[u8]) -> u8 {
(255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1)
}

View File

@@ -1,68 +0,0 @@
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
use vm_memory::ByteValued;
#[repr(packed)]
#[derive(Clone, Copy, Default)]
pub struct Rsdp {
pub signature: [u8; 8],
pub checksum: u8,
pub oem_id: [u8; 6],
pub revision: u8,
_rsdt_addr: u32,
pub length: u32,
pub xsdt_addr: u64,
pub extended_checksum: u8,
_reserved: [u8; 3],
}
// SAFETY: Rsdp only contains a series of integers
unsafe impl ByteValued for Rsdp {}
impl Rsdp {
pub fn new(oem_id: [u8; 6], xsdt_addr: u64) -> Self {
let mut rsdp = Rsdp {
signature: *b"RSD PTR ",
checksum: 0,
oem_id,
revision: 2,
_rsdt_addr: 0,
length: std::mem::size_of::<Rsdp>() as u32,
xsdt_addr,
extended_checksum: 0,
_reserved: [0; 3],
};
rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
rsdp.extended_checksum = super::generate_checksum(rsdp.as_slice());
rsdp
}
pub fn len() -> usize {
std::mem::size_of::<Rsdp>()
}
}
#[cfg(test)]
mod tests {
use super::Rsdp;
use vm_memory::bytes::ByteValued;
#[test]
fn test_rsdp() {
let rsdp = Rsdp::new(*b"CHYPER", 0xdead_beef);
let sum = rsdp
.as_slice()
.iter()
.fold(0u8, |acc, x| acc.wrapping_add(*x));
assert_eq!(sum, 0);
let sum: u8 = rsdp
.as_slice()
.iter()
.fold(0u8, |acc, x| acc.wrapping_add(*x));
assert_eq!(sum, 0);
}
}

View File

@@ -1,147 +0,0 @@
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct GenericAddress {
pub address_space_id: u8,
pub register_bit_width: u8,
pub register_bit_offset: u8,
pub access_size: u8,
pub address: u64,
}
impl GenericAddress {
pub fn io_port_address<T>(address: u16) -> Self {
GenericAddress {
address_space_id: 1,
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
register_bit_offset: 0,
access_size: std::mem::size_of::<T>() as u8,
address: u64::from(address),
}
}
pub fn mmio_address<T>(address: u64) -> Self {
GenericAddress {
address_space_id: 0,
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
register_bit_offset: 0,
access_size: std::mem::size_of::<T>() as u8,
address,
}
}
}
pub struct Sdt {
data: Vec<u8>,
}
#[allow(clippy::len_without_is_empty)]
impl Sdt {
pub fn new(
signature: [u8; 4],
length: u32,
revision: u8,
oem_id: [u8; 6],
oem_table: [u8; 8],
oem_revision: u32,
) -> Self {
assert!(length >= 36);
let mut data = Vec::with_capacity(length as usize);
data.extend_from_slice(&signature);
data.extend_from_slice(&length.to_le_bytes());
data.push(revision);
data.push(0); // checksum
data.extend_from_slice(&oem_id);
data.extend_from_slice(&oem_table);
data.extend_from_slice(&oem_revision.to_le_bytes());
data.extend_from_slice(b"CLDH");
data.extend_from_slice(&0u32.to_le_bytes());
assert_eq!(data.len(), 36);
data.resize(length as usize, 0);
let mut sdt = Sdt { data };
sdt.update_checksum();
sdt
}
pub fn update_checksum(&mut self) {
self.data[9] = 0;
let checksum = super::generate_checksum(self.data.as_slice());
self.data[9] = checksum
}
pub fn as_slice(&self) -> &[u8] {
self.data.as_slice()
}
pub fn append<T>(&mut self, value: T) {
let orig_length = self.data.len();
let new_length = orig_length + std::mem::size_of::<T>();
self.data.resize(new_length, 0);
self.write_u32(4, new_length as u32);
self.write(orig_length, value);
}
pub fn append_slice(&mut self, data: &[u8]) {
let orig_length = self.data.len();
let new_length = orig_length + data.len();
self.write_u32(4, new_length as u32);
self.data.extend_from_slice(data);
self.update_checksum();
}
/// Write a value at the given offset
pub fn write<T>(&mut self, offset: usize, value: T) {
assert!((offset + (std::mem::size_of::<T>() - 1)) < self.data.len());
unsafe {
*(((self.data.as_mut_ptr() as usize) + offset) as *mut T) = value;
}
self.update_checksum();
}
pub fn write_u8(&mut self, offset: usize, val: u8) {
self.write(offset, val);
}
pub fn write_u16(&mut self, offset: usize, val: u16) {
self.write(offset, val);
}
pub fn write_u32(&mut self, offset: usize, val: u32) {
self.write(offset, val);
}
pub fn write_u64(&mut self, offset: usize, val: u64) {
self.write(offset, val);
}
pub fn len(&self) -> usize {
self.data.len()
}
}
#[cfg(test)]
mod tests {
use super::Sdt;
#[test]
fn test_sdt() {
let mut sdt = Sdt::new(*b"TEST", 40, 1, *b"CLOUDH", *b"TESTTEST", 1);
let sum: u8 = sdt
.as_slice()
.iter()
.fold(0u8, |acc, x| acc.wrapping_add(*x));
assert_eq!(sum, 0);
sdt.write_u32(36, 0x12345678);
let sum: u8 = sdt
.as_slice()
.iter()
.fold(0u8, |acc, x| acc.wrapping_add(*x));
assert_eq!(sum, 0);
}
}

View File

@@ -9,15 +9,15 @@ default = []
tdx = []
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.69"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.138"
libc = "0.2.139"
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
log = "0.4.17"
serde = { version = "1.0.150", features = ["rc", "derive"] }
thiserror = "1.0.37"
uuid = "1.2.2"
serde = { version = "1.0.151", features = ["rc", "derive"] }
thiserror = "1.0.38"
uuid = "1.3.0"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }

View File

@@ -191,9 +191,13 @@ fn create_cpu_nodes(
let cpu_map_node = fdt.begin_node("cpu-map")?;
// Create device tree nodes with regard of above mapping.
for cluster_idx in 0..packages {
let cluster_name = format!("cluster{cluster_idx:x}");
let cluster_node = fdt.begin_node(&cluster_name)?;
for package_idx in 0..packages {
let package_name = format!("socket{package_idx:x}");
let package_node = fdt.begin_node(&package_name)?;
// Cluster is the container of cores, and it is mandatory in the CPU topology.
// Add a default "cluster0" in each socket/package.
let cluster_node = fdt.begin_node("cluster0")?;
for core_idx in 0..cores_per_package {
let core_name = format!("core{core_idx:x}");
@@ -202,7 +206,7 @@ fn create_cpu_nodes(
for thread_idx in 0..threads_per_core {
let thread_name = format!("thread{thread_idx:x}");
let thread_node = fdt.begin_node(&thread_name)?;
let cpu_idx = threads_per_core * cores_per_package * cluster_idx
let cpu_idx = threads_per_core * cores_per_package * package_idx
+ threads_per_core * core_idx
+ thread_idx;
fdt.property_u32("cpu", cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
@@ -212,6 +216,7 @@ fn create_cpu_nodes(
fdt.end_node(core_node)?;
}
fdt.end_node(cluster_node)?;
fdt.end_node(package_node)?;
}
fdt.end_node(cpu_map_node)?;
} else {
@@ -259,7 +264,7 @@ fn create_memory_node(
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
// Case 1: all RAM is under the hole
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node = fdt.begin_node("memory")?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
@@ -269,7 +274,7 @@ fn create_memory_node(
// Region 1: RAM before the hole
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
- super::layout::RAM_START.raw_value();
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
@@ -278,10 +283,7 @@ fn create_memory_node(
// Region 2: RAM after the hole
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
let mem_reg_prop = [
super::layout::RAM_64BIT_START.raw_value() as u64,
mem_size as u64,
];
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
let memory_node_name =
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
@@ -303,7 +305,7 @@ fn create_chosen_node(
fdt.property_string("bootargs", cmdline)?;
if let Some(initrd_config) = initrd {
let initrd_start = initrd_config.address.raw_value() as u64;
let initrd_start = initrd_config.address.raw_value();
let initrd_end = initrd_config.address.raw_value() + initrd_config.size as u64;
fdt.property_u64("linux,initrd-start", initrd_start)?;
fdt.property_u64("linux,initrd-end", initrd_end)?;

View File

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

View File

@@ -99,7 +99,7 @@ pub use x86_64::{
#[cfg(target_arch = "x86_64")]
#[inline(always)]
fn pagesize() -> usize {
// Trivially safe
// SAFETY: Trivially safe
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
}

View File

@@ -126,9 +126,11 @@ struct MemmapTableEntryWrapper(hvm_memmap_table_entry);
#[derive(Copy, Clone, Default)]
struct ModlistEntryWrapper(hvm_modlist_entry);
// SAFETY: These data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for StartInfoWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for MemmapTableEntryWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for ModlistEntryWrapper {}
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
@@ -549,13 +551,30 @@ impl CpuidFeatureEntry {
}
pub fn generate_common_cpuid(
hypervisor: Arc<dyn hypervisor::Hypervisor>,
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
topology: Option<(u8, u8, u8)>,
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
phys_bits: u8,
kvm_hyperv: bool,
#[cfg(feature = "tdx")] tdx_enabled: bool,
) -> super::Result<Vec<CpuIdEntry>> {
// SAFETY: cpuid called with valid leaves
if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT {
// SAFETY: cpuid called with valid leaves
let hypervisor_cpuid = unsafe { x86_64::__cpuid(0x4000_0000) };
let mut identifier: [u8; 12] = [0; 12];
identifier[0..4].copy_from_slice(&hypervisor_cpuid.ebx.to_le_bytes()[..]);
identifier[4..8].copy_from_slice(&hypervisor_cpuid.ecx.to_le_bytes()[..]);
identifier[8..12].copy_from_slice(&hypervisor_cpuid.edx.to_le_bytes()[..]);
info!(
"Running under nested virtualisation. Hypervisor string: {}",
String::from_utf8_lossy(&identifier)
);
}
info!("Generating guest CPUID for with physical address size: {phys_bits}");
let cpuid_patches = vec![
// Patch tsc deadline timer bit
CpuidPatch {
@@ -590,7 +609,9 @@ pub fn generate_common_cpuid(
];
// Supported CPUID
let mut cpuid = hypervisor.get_cpuid().map_err(Error::CpuidGetSupported)?;
let mut cpuid = hypervisor
.get_supported_cpuid()
.map_err(Error::CpuidGetSupported)?;
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
@@ -679,6 +700,7 @@ pub fn generate_common_cpuid(
// Copy CPU identification string
for i in 0x8000_0002..=0x8000_0004 {
cpuid.retain(|c| c.function != i);
// SAFETY: call cpuid with valid leaves
let leaf = unsafe { std::arch::x86_64::__cpuid(i) };
cpuid.push(CpuIdEntry {
function: i,
@@ -743,8 +765,7 @@ pub fn generate_common_cpuid(
pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>,
id: u8,
kernel_entry_point: Option<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
cpuid: Vec<CpuIdEntry>,
kvm_hyperv: bool,
) -> super::Result<()> {
@@ -753,13 +774,6 @@ pub fn configure_vcpu(
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
// Set ApicId in cpuid for each vcpu
// SAFETY: get host cpuid when eax=1
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
cpu_ebx &= 0xffffff;
cpu_ebx |= (id as u32) << 24;
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
if !kvm_hyperv {
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
@@ -796,12 +810,12 @@ pub fn configure_vcpu(
}
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
if let Some(kernel_entry_point) = kernel_entry_point {
if let Some((kernel_entry_point, guest_memory)) = boot_setup {
if let Some(entry_addr) = kernel_entry_point.entry_addr {
// Safe to unwrap because this method is called after the VM is configured
regs::setup_regs(vcpu, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
regs::setup_sregs(&vm_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
}
}
interrupts::set_lint(vcpu).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
@@ -1064,6 +1078,7 @@ pub fn initramfs_load_addr(
}
pub fn get_host_cpu_phys_bits() -> u8 {
// SAFETY: call cpuid with valid leaves
unsafe {
let leaf = x86_64::__cpuid(0x8000_0000);
@@ -1174,6 +1189,7 @@ fn update_cpuid_sgx(
// Get host CPUID for leaf 0x12, subleaf 0x2. This is to retrieve EPC
// properties such as confidentiality and integrity.
// SAFETY: call cpuid with valid leaves
let leaf = unsafe { std::arch::x86_64::__cpuid_count(0x12, 0x2) };
for (i, epc_section) in epc_sections.iter().enumerate() {

View File

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

View File

@@ -67,7 +67,7 @@ const PCI_SUPPORTED: u64 = 1 << 7;
const IS_VIRTUAL_MACHINE: u8 = 1 << 4;
fn compute_checksum<T: Copy>(v: &T) -> u8 {
// Safe because we are only reading the bytes within the size of the `T` reference `v`.
// SAFETY: we are only reading the bytes within the size of the `T` reference `v`.
let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
let mut checksum: u8 = 0;
for i in v_slice.iter() {
@@ -145,11 +145,15 @@ struct SmbiosEndOfTable {
handle: u16,
}
// SAFETY: These data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for Smbios30Entrypoint {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosBiosInfo {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosSysInfo {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosOemStrings {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosEndOfTable {}
fn write_and_incr<T: ByteValued>(

View File

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

View File

@@ -8,15 +8,16 @@ edition = "2021"
default = []
[dependencies]
io-uring = "0.5.9"
libc = "0.2.138"
io-uring = "0.5.12"
libc = "0.2.139"
log = "0.4.17"
qcow = { path = "../qcow" }
thiserror = "1.0.37"
smallvec = "1.10.0"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,13 +3,10 @@
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use(crate_version)]
extern crate clap;
use std::process::Command;
fn main() {
let mut version = "v".to_owned() + crate_version!();
let mut version = "v".to_owned() + env!("CARGO_PKG_VERSION");
if let Ok(git_out) = Command::new("git").args(["describe", "--dirty"]).output() {
if git_out.status.success() {

View File

@@ -5,16 +5,15 @@ authors = ["The Chromium OS Authors"]
edition = "2021"
[dependencies]
acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.66"
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.69"
arch = { path = "../arch" }
bitflags = "2.4.1"
bitflags = "1.3.2"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.138"
libc = "0.2.139"
log = "0.4.17"
phf = { version = "0.11.1", features = ["macros"] }
thiserror = "1.0.37"
thiserror = "1.0.38"
tpm = { path = "../tpm" }
versionize = "0.1.9"
versionize_derive = "0.1.4"

View File

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

View File

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

View File

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

View File

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

View File

@@ -106,18 +106,39 @@ impl VersionMapped for GpioState {}
impl Gpio {
/// Constructs an PL061 GPIO device.
pub fn new(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
pub fn new(
id: String,
interrupt: Arc<dyn InterruptSourceGroup>,
state: Option<GpioState>,
) -> Self {
let (data, old_in_data, dir, isense, ibe, iev, im, istate, afsel) =
if let Some(state) = state {
(
state.data,
state.old_in_data,
state.dir,
state.isense,
state.ibe,
state.iev,
state.im,
state.istate,
state.afsel,
)
} else {
(0, 0, 0, 0, 0, 0, 0, 0, 0)
};
Self {
id,
data: 0,
old_in_data: 0,
dir: 0,
isense: 0,
ibe: 0,
iev: 0,
im: 0,
istate: 0,
afsel: 0,
data,
old_in_data,
dir,
isense,
ibe,
iev,
im,
istate,
afsel,
interrupt,
}
}
@@ -136,24 +157,12 @@ impl Gpio {
}
}
fn set_state(&mut self, state: &GpioState) {
self.data = state.data;
self.old_in_data = state.old_in_data;
self.dir = state.dir;
self.isense = state.isense;
self.ibe = state.ibe;
self.iev = state.iev;
self.im = state.im;
self.istate = state.istate;
self.afsel = state.afsel;
}
fn pl061_internal_update(&mut self) {
// FIXME:
// Missing Output Interrupt Emulation.
// Input Edging Interrupt Emulation.
let changed = ((self.old_in_data ^ self.data) & !self.dir) as u32;
let changed = (self.old_in_data ^ self.data) & !self.dir;
if changed > 0 {
self.old_in_data = self.data;
for i in 0..N_GPIOS {
@@ -319,12 +328,7 @@ impl Snapshottable for Gpio {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id, &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -378,6 +382,7 @@ mod tests {
let mut gpio = Gpio::new(
String::from(GPIO_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
let mut data = [0; 4];

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,13 +8,11 @@ use anyhow::anyhow;
use arch::aarch64::layout::{TPM_SIZE, TPM_START};
#[cfg(target_arch = "x86_64")]
use arch::x86_64::layout::{TPM_SIZE, TPM_START};
use phf::phf_map;
use std::cmp;
use std::sync::{Arc, Barrier};
use thiserror::Error;
use tpm::emulator::{BackendCmd, Emulator};
use tpm::TPM_CRB_BUFFER_MAX;
use tpm::TPM_SUCCESS;
use vm_device::BusDevice;
#[derive(Error, Debug)]
@@ -23,62 +21,135 @@ pub enum Error {
CheckCaps(#[source] anyhow::Error),
#[error("Failed to initialize tpm: {0}")]
Init(#[source] anyhow::Error),
#[error("Failed to deliver tpm Command: {0}")]
DeliverRequest(#[source] anyhow::Error),
}
type Result<T> = anyhow::Result<T, Error>;
#[allow(dead_code)]
enum LocStateFields {
TpmEstablished,
LocAssigned,
ActiveLocality,
Reserved,
TpmRegValidSts,
}
enum LocStsFields {
Granted,
BeenSeized,
}
#[allow(dead_code)]
enum IntfIdFields {
InterfaceType,
InterfaceVersion,
CapLocality,
CapCRBIdleBypass,
Reserved1,
CapDataXferSizeSupport,
CapFIFO,
CapCRB,
CapIFRes,
InterfaceSelector,
IntfSelLock,
Reserved2,
Rid,
}
#[allow(dead_code)]
enum IntfId2Fields {
Vid,
Did,
}
enum CtrlStsFields {
TpmSts,
TpmIdle,
}
enum CrbRegister {
LocState(LocStateFields),
LocSts(LocStsFields),
IntfId(IntfIdFields),
IntfId2(IntfId2Fields),
CtrlSts(CtrlStsFields),
}
/* crb 32-bit registers */
const CRB_LOC_STATE: u32 = 0x0;
//Register Fields
// Field => (start, length)
// start: lowest bit in the bit field numbered from 0
// Field => (base, offset, length)
// base: starting position of the register
// offset: lowest bit in the bit field numbered from 0
// length: length of the bit field
const CRB_LOC_STATE_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
"tpmEstablished" => [0, 1],
"locAssigned" => [1,1],
"activeLocality"=> [2, 3],
"reserved" => [5, 2],
"tpmRegValidSts" => [7, 1]
};
const fn get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32) {
let (offset, len) = match f {
LocStateFields::TpmEstablished => (0, 1),
LocStateFields::LocAssigned => (1, 1),
LocStateFields::ActiveLocality => (2, 3),
LocStateFields::Reserved => (5, 2),
LocStateFields::TpmRegValidSts => (7, 1),
};
(CRB_LOC_STATE, offset, len)
}
const CRB_LOC_CTRL: u32 = 0x08;
const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
const CRB_LOC_STS: u32 = 0x0C;
const CRB_LOC_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
"Granted" => [0, 1],
"beenSeized" => [1,1]
};
const fn get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32) {
let (offset, len) = match f {
LocStsFields::Granted => (0, 1),
LocStsFields::BeenSeized => (1, 1),
};
(CRB_LOC_STS, offset, len)
}
const CRB_INTF_ID: u32 = 0x30;
const CRB_INTF_ID_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
"InterfaceType" => [0, 4],
"InterfaceVersion" => [4, 4],
"CapLocality" => [8, 1],
"CapCRBIdleBypass" => [9, 1],
"Reserved1" => [10, 1],
"CapDataXferSizeSupport" => [11, 2],
"CapFIFO" => [13, 1],
"CapCRB" => [14, 1],
"CapIFRes" => [15, 2],
"InterfaceSelector" => [17, 2],
"IntfSelLock" => [19, 1],
"Reserved2" => [20, 4],
"RID" => [24, 8]
};
const fn get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32) {
let (offset, len) = match f {
IntfIdFields::InterfaceType => (0, 4),
IntfIdFields::InterfaceVersion => (4, 4),
IntfIdFields::CapLocality => (8, 1),
IntfIdFields::CapCRBIdleBypass => (9, 1),
IntfIdFields::Reserved1 => (10, 1),
IntfIdFields::CapDataXferSizeSupport => (11, 2),
IntfIdFields::CapFIFO => (13, 1),
IntfIdFields::CapCRB => (14, 1),
IntfIdFields::CapIFRes => (15, 2),
IntfIdFields::InterfaceSelector => (17, 2),
IntfIdFields::IntfSelLock => (19, 1),
IntfIdFields::Reserved2 => (20, 4),
IntfIdFields::Rid => (24, 8),
};
(CRB_INTF_ID, offset, len)
}
const CRB_INTF_ID2: u32 = 0x34;
const CRB_INTF_ID2_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
"VID" => [0, 16],
"DID" => [16, 16]
};
const fn get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32) {
let (offset, len) = match f {
IntfId2Fields::Vid => (0, 16),
IntfId2Fields::Did => (16, 16),
};
(CRB_INTF_ID2, offset, len)
}
const CRB_CTRL_REQ: u32 = 0x40;
const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
const CRB_CTRL_STS: u32 = 0x44;
const CRB_CTRL_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
"tpmSts" => [0, 1],
"tpmIdle" => [1, 1]
};
const fn get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32) {
let (offset, len) = match f {
CtrlStsFields::TpmSts => (0, 1),
CtrlStsFields::TpmIdle => (1, 1),
};
(CRB_CTRL_STS, offset, len)
}
const CRB_CTRL_CANCEL: u32 = 0x48;
const CRB_CANCEL_INVOKE: u32 = 1 << 0;
const CRB_CTRL_START: u32 = 0x4C;
@@ -94,7 +165,7 @@ const TPM_CRB_NO_LOCALITY: u32 = 0xff;
const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
const TPM_CRB_R_MAX: u32 = CRB_DATA_BUFFER;
const TPM_CRB_R_MAX: usize = CRB_DATA_BUFFER as usize;
// CRB Protocol details
const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
@@ -109,47 +180,29 @@ const PCI_VENDOR_ID_IBM: u32 = 0x1014;
const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> {
// Returns (register base, offset, len)
const fn get_field(reg: CrbRegister) -> (u32, u32, u32) {
match reg {
CRB_LOC_STATE => CRB_LOC_STATE_FIELDS,
CRB_LOC_STS => CRB_LOC_STS_FIELDS,
CRB_INTF_ID => CRB_INTF_ID_FIELDS,
CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS,
CRB_CTRL_STS => CRB_CTRL_STS_FIELDS,
_ => {
panic!("Fields in '{reg:?}' register were accessed which are Invalid");
}
CrbRegister::LocState(f) => get_crb_loc_state_field(f),
CrbRegister::LocSts(f) => get_crb_loc_sts_field(f),
CrbRegister::IntfId(f) => get_crb_intf_id_field(f),
CrbRegister::IntfId2(f) => get_crb_intf_id2_field(f),
CrbRegister::CtrlSts(f) => get_crb_ctrl_sts_field(f),
}
}
/// Set a particular field in a Register
fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str, value: u32) {
let reg_fields = get_fields_map(reg);
if reg_fields.contains_key(field) {
let start = reg_fields.get(field).unwrap()[0];
let len = reg_fields.get(field).unwrap()[1];
let mask = (!(0_u32) >> (32 - len)) << start;
regs[reg as usize] = (regs[reg as usize] & !mask) | ((value << start) & mask);
} else {
error!(
"Failed to tpm Register. {:?} is not a valid field in Reg {:#X}",
field, reg
)
}
// Set a particular field in a Register
fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32) {
let (base, offset, len) = get_field(reg);
let mask = (!(0_u32) >> (32 - len)) << offset;
regs[base as usize] = (regs[base as usize] & !mask) | ((value << offset) & mask);
}
/// Get the value of a particular field in a Register
fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str) -> u32 {
let reg_fields = get_fields_map(reg);
if reg_fields.contains_key(field) {
let start = reg_fields.get(field).unwrap()[0];
let len = reg_fields.get(field).unwrap()[1];
let mask = (!(0_u32) >> (32 - len)) << start;
(regs[reg as usize] & mask) >> start
} else {
// TODO: Sensible return value if fields do not exist
0x0
}
// Get the value of a particular field in a Register
const fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32 {
let (base, offset, len) = get_field(reg);
let mask = (!(0_u32) >> (32 - len)) << offset;
(regs[base as usize] & mask) >> offset
}
fn locality_from_addr(addr: u32) -> u8 {
@@ -158,8 +211,7 @@ fn locality_from_addr(addr: u32) -> u8 {
pub struct Tpm {
emulator: Emulator,
cmd: Option<BackendCmd>,
regs: [u32; TPM_CRB_R_MAX as usize],
regs: [u32; TPM_CRB_R_MAX],
backend_buff_size: usize,
data_buff: [u8; TPM_CRB_BUFFER_MAX],
data_buff_len: usize,
@@ -171,8 +223,7 @@ impl Tpm {
.map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
let mut tpm = Tpm {
emulator,
cmd: None,
regs: [0; TPM_CRB_R_MAX as usize],
regs: [0; TPM_CRB_R_MAX],
backend_buff_size: TPM_CRB_BUFFER_MAX,
data_buff: [0; TPM_CRB_BUFFER_MAX],
data_buff_len: 0,
@@ -182,74 +233,93 @@ impl Tpm {
}
fn get_active_locality(&mut self) -> u32 {
if get_reg_field(&self.regs, CRB_LOC_STATE, "locAssigned") == 0 {
if get_reg_field(
&self.regs,
CrbRegister::LocState(LocStateFields::LocAssigned),
) == 0
{
return TPM_CRB_NO_LOCALITY;
}
get_reg_field(&self.regs, CRB_LOC_STATE, "activeLocality")
get_reg_field(
&self.regs,
CrbRegister::LocState(LocStateFields::ActiveLocality),
)
}
fn request_completed(&mut self, result: isize) {
fn request_completed(&mut self, success: bool) {
self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
if result != 0 {
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmSts", 1);
if !success {
set_reg_field(
&mut self.regs,
CrbRegister::CtrlSts(CtrlStsFields::TpmSts),
1,
);
}
}
fn reset(&mut self) -> Result<()> {
let cur_buff_size = self.emulator.get_buffer_size().unwrap();
self.regs = [0; TPM_CRB_R_MAX as usize];
set_reg_field(&mut self.regs, CRB_LOC_STATE, "tpmRegValidSts", 1);
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
let cur_buff_size = self.emulator.get_buffer_size();
self.regs = [0; TPM_CRB_R_MAX];
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"InterfaceType",
CrbRegister::LocState(LocStateFields::TpmRegValidSts),
1,
);
set_reg_field(
&mut self.regs,
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
1,
);
set_reg_field(
&mut self.regs,
CrbRegister::IntfId(IntfIdFields::InterfaceType),
CRB_INTF_TYPE_CRB_ACTIVE,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"InterfaceVersion",
CrbRegister::IntfId(IntfIdFields::InterfaceVersion),
CRB_INTF_VERSION_CRB,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"CapLocality",
CrbRegister::IntfId(IntfIdFields::CapLocality),
CRB_INTF_CAP_LOCALITY_0_ONLY,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"CapCRBIdleBypass",
CrbRegister::IntfId(IntfIdFields::CapCRBIdleBypass),
CRB_INTF_CAP_IDLE_FAST,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"CapDataXferSizeSupport",
CrbRegister::IntfId(IntfIdFields::CapDataXferSizeSupport),
CRB_INTF_CAP_XFER_SIZE_64,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"CapFIFO",
CrbRegister::IntfId(IntfIdFields::CapFIFO),
CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"CapCRB",
CrbRegister::IntfId(IntfIdFields::CapCRB),
CRB_INTF_CAP_CRB_SUPPORTED,
);
set_reg_field(
&mut self.regs,
CRB_INTF_ID,
"InterfaceSelector",
CrbRegister::IntfId(IntfIdFields::InterfaceSelector),
CRB_INTF_IF_SELECTOR_CRB,
);
set_reg_field(&mut self.regs, CRB_INTF_ID, "RID", 0b0000);
set_reg_field(&mut self.regs, CRB_INTF_ID2, "VID", PCI_VENDOR_ID_IBM);
set_reg_field(
&mut self.regs,
CrbRegister::IntfId(IntfIdFields::Rid),
0b0000,
);
set_reg_field(
&mut self.regs,
CrbRegister::IntfId2(IntfId2Fields::Vid),
PCI_VENDOR_ID_IBM,
);
self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
@@ -268,7 +338,6 @@ impl Tpm {
}
}
//impl BusDevice for TPM
impl BusDevice for Tpm {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
let mut offset: u32 = offset as u32;
@@ -367,10 +436,18 @@ impl BusDevice for Tpm {
}
CRB_CTRL_REQ => match v {
CRB_CTRL_REQ_CMD_READY => {
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 0);
set_reg_field(
&mut self.regs,
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
0,
);
}
CRB_CTRL_REQ_GO_IDLE => {
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
set_reg_field(
&mut self.regs,
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
1,
);
}
_ => {
error!("Invalid value passed to CRTL_REQ register");
@@ -393,27 +470,14 @@ impl BusDevice for Tpm {
{
self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
self.cmd = Some(BackendCmd {
locality: locality as u8,
input: self.data_buff[0..self.data_buff_len].to_vec(),
let mut cmd = BackendCmd {
buffer: &mut self.data_buff,
input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
output: self.data_buff.to_vec(),
output_len: TPM_CRB_BUFFER_MAX,
selftest_done: false,
});
};
let mut cmd = self.cmd.as_ref().unwrap().clone();
let output = self.emulator.deliver_request(&mut cmd).map_err(|e| {
Error::DeliverRequest(anyhow!(
"Failed to deliver tpm request. Error :{:?}",
e
))
});
//TODO: drop the copy here
self.data_buff.fill(0);
self.data_buff.clone_from_slice(output.unwrap().as_slice());
let status = self.emulator.deliver_request(&mut cmd).is_ok();
self.request_completed(TPM_SUCCESS as isize);
self.request_completed(status);
}
}
CRB_LOC_CTRL => {
@@ -424,13 +488,33 @@ impl BusDevice for Tpm {
match v {
CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
CRB_LOC_CTRL_RELINQUISH => {
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 0);
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 0);
set_reg_field(
&mut self.regs,
CrbRegister::LocState(LocStateFields::LocAssigned),
0,
);
set_reg_field(
&mut self.regs,
CrbRegister::LocSts(LocStsFields::Granted),
0,
);
}
CRB_LOC_CTRL_REQUEST_ACCESS => {
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 1);
set_reg_field(&mut self.regs, CRB_LOC_STS, "beenSeized", 0);
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 1);
set_reg_field(
&mut self.regs,
CrbRegister::LocSts(LocStsFields::Granted),
1,
);
set_reg_field(
&mut self.regs,
CrbRegister::LocSts(LocStsFields::BeenSeized),
0,
);
set_reg_field(
&mut self.regs,
CrbRegister::LocState(LocStateFields::LocAssigned),
1,
);
}
_ => {
error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
@@ -456,10 +540,10 @@ mod tests {
#[test]
fn test_set_get_reg_field() {
let mut regs: [u32; TPM_CRB_R_MAX as usize] = [0; TPM_CRB_R_MAX as usize];
set_reg_field(&mut regs, CRB_INTF_ID, "RID", 0xAC);
let mut regs: [u32; TPM_CRB_R_MAX] = [0; TPM_CRB_R_MAX];
set_reg_field(&mut regs, CrbRegister::IntfId(IntfIdFields::Rid), 0xAC);
assert_eq!(
get_reg_field(&regs, CRB_INTF_ID, "RID"),
get_reg_field(&regs, CrbRegister::IntfId(IntfIdFields::Rid)),
0xAC,
concat!("Test: ", stringify!(set_get_reg_field))
);

View File

@@ -217,7 +217,7 @@ From the CLI, one can either:
The REST API and the CLI both rely on a common, [internal API](#internal-api).
The CLI options are parsed by the
[clap crate](https://docs.rs/clap/2.33.0/clap/) and then translated into
[argh crate](https://docs.rs/argh/latest/argh/) and then translated into
[internal API](#internal-api) commands.
The REST API is processed by an HTTP thread using the
@@ -245,7 +245,7 @@ As a summary, the REST API and the CLI are essentially frontends for the
| | +------------------------+
| +----------+ | VMM
| CLI | | |
+----------->+ clap +--------------+
+----------->+ argh +--------------+
| |
+----------+

View File

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

View File

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

View File

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

View File

@@ -36,7 +36,7 @@ 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.
To do so we need to start `cloud-hypervisor` with the right debug level
(`-vvv`). It is also recommended to have it log into a dedicated file in order
(`-v -v -v`). It is also recommended to have it log into a dedicated file in order
to easily grep for the tracing logs (e.g.
`--log-file /tmp/cloud-hypervisor.log`):
@@ -48,7 +48,7 @@ to easily grep for the tracing logs (e.g.
--memory size=1024M \
--rng \
--log-file /tmp/ch-fw.log \
-vvv
-v -v -v
```
After booting the guest, we then have to grep for the debug I/O port traces in

View File

@@ -8,7 +8,7 @@ To enable debugging with GDB, build with the `guest_debug` feature enabled:
cargo build --features guest_debug
```
To use the `--gdb` option, specify the Unix Domain Socket with `--path` that Cloud Hypervisor will use to communicate with the host's GDB:
To use the `--gdb` option, specify the Unix Domain Socket with `path` that Cloud Hypervisor will use to communicate with the host's GDB:
```bash
./cloud-hypervisor \

41
docs/heap-profiling.md Normal file
View File

@@ -0,0 +1,41 @@
# Heap profiling
Cloud Hypervisor supports generating a profile using
[dhat](https://docs.rs/dhat/latest/dhat/) of the heap allocations made during
the runtime of the process.
## Building a suitable binary
This adds the symbol information to the release binary but does not otherwise
affect the performance.
```
$ cargo build --profile profiling --features "dhat-heap"
```
## Generating output
Cloud Hypervisor can then be run as usual. However it is necessary to run with `--seccomp false` as the profiling requires extra syscalls.
```
$ target/profiling/cloud-hypervisor \
--kernel ~/src/linux/vmlinux \
--pmem file=~/workloads/focal.raw \
--cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \
--api-socket /tmp/api1 \
--seccomp false
```
When the VMM exits a message like the following will be shown:
```
dhat: Total: 384,582 bytes in 3,512 blocks
dhat: At t-gmax: 133,885 bytes in 379 blocks
dhat: At t-end: 12,160 bytes in 20 blocks
dhat: The data has been saved to dhat-heap.json, and is viewable with dhat/dh_view.html
```
The JSON output can then be uploaded to [the dh_view tool](https://nnethercote.github.io/dh_view/dh_view.html) for analysis.

View File

@@ -4,7 +4,7 @@ Currently Cloud Hypervisor supports hot plugging of CPUs devices (x86 only), PCI
## Kernel support
For hotplug on Cloud Hypervisor ACPI GED support is needed. This can either be achieved by turning on `CONFIG_ACPI_REDUCED_HARDWARE_ONLY`
For hotplug on Cloud Hypervisor ACPI GED support is needed. This can either be achieved by turning on `CONFIG_ACPI_REDUCED_HARDWARE_ONLY`
or by using this kernel patch (available in 5.5-rc1 and later): https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/drivers/acpi/Makefile?id=ac36d37e943635fc072e9d4f47e40a48fbcdb3f0
## CPU Hot Plug
@@ -27,16 +27,16 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--memory size=1024M \
--net "tap=,mac=,ip=,mask=" \
--rng \
--api-socket=/tmp/ch-socket
--api-socket /tmp/ch-socket
$ popd
```
Notice the addition of `--api-socket=/tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
Notice the addition of `--api-socket /tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
To ask the VMM to add additional vCPUs then use the resize API:
```shell
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 8
./ch-remote --api-socket /tmp/ch-socket resize --cpus 8
```
The extra vCPU threads will be created and advertised to the running kernel. The kernel does not bring up the CPUs immediately and instead the user must "online" them from inside the VM:
@@ -56,7 +56,7 @@ After a reboot the added CPUs will remain.
Removing CPUs works similarly by reducing the number in the "desired_vcpus" field of the reisze API. The CPUs will be automatically offlined inside the guest so there is no need to run any commands inside the guest:
```shell
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 2
./ch-remote --api-socket /tmp/ch-socket resize --cpus 2
```
As per adding CPUs to the guest, after a reboot the VM will be running with the reduced number of vCPUs.
@@ -85,7 +85,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--memory size=1024M,hotplug_size=8192M \
--net "tap=,mac=,ip=,mask=" \
--rng \
--api-socket=/tmp/ch-socket
--api-socket /tmp/ch-socket
$ popd
```
@@ -98,7 +98,7 @@ root@ch-guest ~ # echo online | sudo tee /sys/devices/system/memory/auto_online_
To ask the VMM to expand the RAM for the VM:
```shell
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G
./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
```
The new memory is now available to use inside the VM:
@@ -134,14 +134,14 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--disk path=focal-server-cloudimg-amd64.raw \
--memory size=1024M,hotplug_size=8192M,hotplug_method=virtio-mem \
--net "tap=,mac=,ip=,mask=" \
--api-socket=/tmp/ch-socket
--api-socket /tmp/ch-socket
$ popd
```
To ask the VMM to expand the RAM for the VM (request is in bytes):
```shell
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G
./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
```
The new memory is now available to use inside the VM:
@@ -159,7 +159,7 @@ The same API can also be used to reduce the desired RAM for a VM. It is importan
Extra PCI devices can be added and removed from a running `cloud-hypervisor` instance. This is controlled by making a HTTP API request to the VMM to ask for the additional device to be added, or for the existing device to be removed.
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](arm64.md#uefi-booting) for more information.
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](uefi.md#building-uefi-firmware-for-aarch64) for more information.
To use PCI device hotplug start the VM with the HTTP server.
@@ -172,17 +172,17 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--cpus boot=4 \
--memory size=1024M \
--net "tap=,mac=,ip=,mask=" \
--api-socket=/tmp/ch-socket
--api-socket /tmp/ch-socket
```
Notice the addition of `--api-socket=/tmp/ch-socket`.
Notice the addition of `--api-socket /tmp/ch-socket`.
### Add VFIO Device
To ask the VMM to add additional VFIO device then use the `add-device` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/
./ch-remote --api-socket /tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/
```
### Add Disk Device
@@ -190,7 +190,7 @@ To ask the VMM to add additional VFIO device then use the `add-device` API.
To ask the VMM to add additional disk device then use the `add-disk` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-disk path=/foo/bar/cloud.img
./ch-remote --api-socket /tmp/ch-socket add-disk path=/foo/bar/cloud.img
```
### Add Fs Device
@@ -198,7 +198,7 @@ To ask the VMM to add additional disk device then use the `add-disk` API.
To ask the VMM to add additional fs device then use the `add-fs` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock
./ch-remote --api-socket /tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock
```
### Add Net Device
@@ -206,7 +206,7 @@ To ask the VMM to add additional fs device then use the `add-fs` API.
To ask the VMM to add additional network device then use the `add-net` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-net tap=chtap0
./ch-remote --api-socket /tmp/ch-socket add-net tap=chtap0
```
### Add Pmem Device
@@ -214,7 +214,7 @@ To ask the VMM to add additional network device then use the `add-net` API.
To ask the VMM to add additional PMEM device then use the `add-pmem` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-pmem file=/foo/bar.cloud.img
./ch-remote --api-socket /tmp/ch-socket add-pmem file=/foo/bar.cloud.img
```
### Add Vsock Device
@@ -222,7 +222,7 @@ To ask the VMM to add additional PMEM device then use the `add-pmem` API.
To ask the VMM to add additional vsock device then use the `add-vsock` API.
```shell
./ch-remote --api-socket=/tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock
./ch-remote --api-socket /tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock
```
### Common Across All PCI Devices
@@ -244,7 +244,7 @@ After a reboot the added PCI device will remain.
Removing a PCI device works the same way for all kind of PCI devices. The unique identifier related to the device must be provided. This identifier can be provided by the user when adding the new device, or by default Cloud Hypervisor will assign one.
```shell
./ch-remote --api-socket=/tmp/ch-socket remove-device _disk0
./ch-remote --api-socket /tmp/ch-socket remove-device _disk0
```
As per adding a PCI device to the guest, after a reboot the VM will be running without the removed PCI device.

View File

@@ -2,49 +2,64 @@
Intel® Trust Domain Extensions (Intel® TDX) is an Intel technology designed to
isolate virtual machines from the VMM, hypervisor and any other software on the
host platform.
host platform. Here are some useful links:
For more information about TDX technical aspects, design and specification
please refer to the
[TDX Homepage](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html).
* [TDX Homepage](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html):
more information about TDX technical aspects, design and specification
The required Linux changes for the host side can be found in the
[KVM TDX tree](https://github.com/intel/tdx/tree/kvm) while the changes for
the guest side can be found in the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
* [KVM TDX tree](https://github.com/intel/tdx/tree/kvm): the required
Linux kernel changes for the host side
The TDVF firmware can be found in the
[EDK2 staging project](https://github.com/tianocore/edk2-staging/tree/TDVF).
* [Guest TDX tree](https://github.com/intel/tdx/tree/guest): the Linux
kernel changes for the guest side
The TDShim firmware can be found in the
[Confidential Containers project](https://github.com/confidential-containers/td-shim).
* [EDK2 project](https://github.com/tianocore/edk2): the TDVF firmware
* [Confidential Containers project](https://github.com/confidential-containers/td-shim):
the TDShim firmware
* [TDX Tools](https://github.com/intel/tdx-tools): a collection of tools
and scripts to setup TDX environment for testing purpose (such as
installing required packages on the host, creating guest images, and
building the custom Linux kernel for TDX host and guest)
## Cloud Hypervisor support
First, you must be running on a machine with TDX enabled in hardware, and
It is required to use a machine with TDX enabled in hardware and
with the host OS compiled from the [KVM TDX tree](https://github.com/intel/tdx/tree/kvm).
The host environment can also be setup with the [TDX Tools](https://github.com/intel/tdx-tools).
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware,
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware ([TDVF](https://github.com/tianocore/edk2)),
which will then load the guest kernel from the image. The image must be custom
as it must include a kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
Cloud Hypervisor can also boot a TDX VM with direct kernel boot using [TDshim](https://github.com/confidential-containers/td-shim).
The custom Linux kernel for the guest can be built with the [TDX Tools](https://github.com/intel/tdx-tools).
> **Note**
> The latest version of custom host and guest kernel being tested is
> from [TDX Tools - 2023ww01](https://github.com/intel/tdx-tools/commits/2023ww01).
### TDVF
> **Note**
> The latest version of TDVF being tested is [_13b9773_](https://github.com/tianocore/edk2/commit/13b97736c876919b9786055829caaa4fa46984b7).
The firmware can be built as follows:
```bash
git clone https://github.com/tianocore/edk2-staging.git
cd edk2-staging
git checkout origin/TDVF
git clone https://github.com/tianocore/edk2.git
cd edk2
git checkout 13b97736c876919b9786055829caaa4fa46984b7
git submodule update --init --recursive
make -C BaseTools
source ./edksetup.sh
build -p OvmfPkg/OvmfCh.dsc -a X64 -t GCC5 -b RELEASE
build -p OvmfPkg/IntelTdx/IntelTdxX64.dsc -a X64 -t GCC5 -b RELEASE
```
If debug logs are needed, here is the alternative command:
```bash
build -p OvmfPkg/OvmfCh.dsc -a X64 -t GCC5 -D DEBUG_ON_SERIAL_PORT=TRUE
build -p OvmfPkg/IntelTdx/IntelTdxX64.dsc -a X64 -t GCC5 -D DEBUG_ON_SERIAL_PORT=TRUE
```
On the Cloud Hypervisor side, all you need is to build the project with the
@@ -62,7 +77,7 @@ meaning it will be printing guest kernel logs to the `virtio-console` device.
```bash
./cloud-hypervisor \
--platform tdx=on
--firmware edk2-staging/Build/OvmfCh/RELEASE_GCC5/FV/OVMF.fd \
--firmware edk2/Build/IntelTdx/RELEASE_GCC5/FV/OVMF.fd \
--cpus boot=1 \
--memory size=1G \
--disk path=tdx_guest_img
@@ -74,7 +89,7 @@ firmware:
```bash
./cloud-hypervisor \
--platform tdx=on
--firmware edk2-staging/Build/OvmfCh/DEBUG_GCC5/FV/OVMF.fd \
--firmware edk2/Build/IntelTdx/DEBUG_GCC5/FV/OVMF.fd \
--cpus boot=1 \
--memory size=1G \
--disk path=tdx_guest_img \
@@ -84,21 +99,60 @@ firmware:
### TDShim
> **Note**
> 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
direct kernel boot, which is useful for containers use cases.
You can find the instructions for building the firmware directly from the
project [documentation](https://github.com/confidential-containers/td-shim/tree/staging#how-to-build).
To build TDShim from source, it is required to install `Rust`, `NASM`,
and `LLVM` first. The TDshim can be build as follows:
```bash
git clone https://github.com/confidential-containers/td-shim
cd td-shim
git checkout 66bb33451befbf1291abe3cfea7ee9e99d922b0d
cargo install cargo-xbuild
export CC=clang
export AR=llvm-ar
export CC_x86_64_unknown_none=clang
export AR_x86_64_unknown_none=llvm-ar
git submodule update --init --recursive
./sh_script/preparation.sh
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
commands:
```bash
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
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest)
or the [TDX Tools](https://github.com/intel/tdx-tools).
The appropriate kernel boot options must be provided through the `--cmdline`
option as well.
```bash
./cloud-hypervisor \
--platform tdx=on
--firmware tdshim \
--firmware td-shim/target/release/final.bin \
--kernel bzImage \
--cmdline "root=/dev/vda3 console=hvc0 rw"
--cpus boot=1 \
--memory size=1G \
--disk path=tdx_guest_img
```
And here is the alternative command when looking for debug logs from the
TDShim:
```bash
./cloud-hypervisor \
--platform tdx=on
--firmware td-shim/target/debug/final.bin \
--kernel bzImage \
--cmdline "root=/dev/vda3 console=hvc0 rw"
--cpus boot=1 \

View File

@@ -245,7 +245,7 @@ e.g.
```bash
./cloud-hypervisor \
--api-socket=/tmp/api \
--api-socket /tmp/api \
--cpus boot=1 \
--memory size=4G,hugepages=on \
--disk path=focal-server-cloudimg-amd64.raw \
@@ -260,7 +260,7 @@ requiring the IOMMU then may be hotplugged:
e.g.
```bash
./ch-remote --api-socket=/tmp/api add-device path=/sys/bus/pci/devices/0000:00:04.0,iommu=on,pci_segment=1
./ch-remote --api-socket /tmp/api add-device path=/sys/bus/pci/devices/0000:00:04.0,iommu=on,pci_segment=1
```
Devices that cannot be placed behind an IOMMU (e.g. lacking an `iommu=` option)

View File

@@ -16,22 +16,22 @@ $ target/release/cloud-hypervisor
--disk path=~/workloads/focal.raw \
--cpus boot=1 --memory size=1G,shared=on \
--cmdline "root=/dev/vda1 console=ttyS0" \
--serial tty --console off --api-socket=/tmp/api1
--serial tty --console off --api-socket /tmp/api1
```
Launch the destination VM from the same directory (on the host machine):
```bash
$ target/release/cloud-hypervisor --api-socket=/tmp/api2
$ target/release/cloud-hypervisor --api-socket /tmp/api2
```
Get ready for receiving migration for the destination VM (on the host machine):
```bash
$ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock
$ target/release/ch-remote --api-socket /tmp/api2 receive-migration unix:/tmp/sock
```
Start to send migration for the source VM (on the host machine):
```bash
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration --local unix:/tmp/sock
$ target/release/ch-remote --api-socket /tmp/api1 send-migration --local unix:/tmp/sock
```
When the above commands completed, the source VM should be successfully
@@ -51,7 +51,7 @@ $ sudo /target/release/cloud-hypervisor \
--cpus boot=1 --memory size=512M \
--kernel vmlinux \
--cmdline "root=/dev/vda1 console=ttyS0" \
--disk path=focal-1.raw path=focal-nested.raw path=tmp.img\
--disk path=focal-1.raw path=focal-nested.raw --disk path=tmp.img\
--net ip=192.168.101.1
```
@@ -63,7 +63,7 @@ $ sudo /target/release/cloud-hypervisor \
--cpus boot=1 --memory size=512M \
--kernel vmlinux \
--cmdline "root=/dev/vda1 console=ttyS0" \
--disk path=focal-2.raw path=focal-nested.raw path=tmp.img\
--disk path=focal-2.raw path=focal-nested.raw --disk path=tmp.img\
--net ip=192.168.102.1
```
@@ -74,8 +74,8 @@ vm-1:~$ sudo ./cloud-hypervisor \
--memory size=128M \
--kernel vmlinux \
--cmdline "console=ttyS0 root=/dev/vda1" \
--disk path=/dev/vdb path=/dev/vdc \
--api-socket=/tmp/api1 \
--disk path=/dev/vdb --disk path=/dev/vdc \
--api-socket /tmp/api1 \
--net ip=192.168.100.1
vm-1:~$ # setup the guest network if needed
vm-1:~$ sudo ip addr add 192.168.101.2/24 dev ens4
@@ -108,7 +108,7 @@ echo "tmp = $tmp"
Launch the nested destination VM (inside the guest OS of the VM 2):
```bash
vm-2:~$ sudo ./cloud-hypervisor --api-socket=/tmp/api2
vm-2:~$ sudo ./cloud-hypervisor --api-socket /tmp/api2
vm-2:~$ # setup the guest network with the following commands if needed
vm-2:~$ sudo ip addr add 192.168.102.2/24 dev ens4
vm-2:~$ sudo ip link set up dev ens4
@@ -122,7 +122,7 @@ vm-2:~$ ping 192.168.101.2 # This should succeed
Get ready for receiving migration for the nested destination VM (inside
the guest OS of the VM 2):
```bash
vm-2:~$ sudo ./ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock2
vm-2:~$ sudo ./ch-remote --api-socket /tmp/api2 receive-migration unix:/tmp/sock2
vm-2:~$ sudo socat TCP-LISTEN:6000,reuseaddr UNIX-CLIENT:/tmp/sock2
```
@@ -130,7 +130,7 @@ Start to send migration for the nested source VM (inside the guest OS of
the VM 1):
```bash
vm-1:~$ sudo socat UNIX-LISTEN:/tmp/sock1,reuseaddr TCP:192.168.102.2:6000
vm-1:~$ sudo ./ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock1
vm-1:~$ sudo ./ch-remote --api-socket /tmp/api1 send-migration unix:/tmp/sock1
```
When the above commands completed, the source VM should be successfully

View File

@@ -38,6 +38,6 @@ This level is for the benefit of developers. It should be used for sporadic and
### `debug!()`
Use `-vv` to enable.
Use `-v -v` to enable.
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.

View File

@@ -519,7 +519,7 @@ different distances, it can be described with the following example.
_Example_
```
--numa guest_numa_id=0,distances=[1@15,2@25] guest_numa_id=1,distances=[0@15,2@20] guest_numa_id=2,distances=[0@25,1@20]
--numa guest_numa_id=0,distances=[1@15,2@25] --numa guest_numa_id=1,distances=[0@15,2@20] guest_numa_id=2,distances=[0@25,1@20]
```
### `memory_zones`
@@ -543,14 +543,14 @@ demarcate the list.
Note that a memory zone must belong to a single NUMA node. The following
configuration is incorrect, therefore not allowed:
`--numa guest_numa_id=0,memory_zones=mem0 guest_numa_id=1,memory_zones=mem0`
`--numa guest_numa_id=0,memory_zones=mem0 --numa guest_numa_id=1,memory_zones=mem0`
_Example_
```
--memory size=0
--memory-zone id=mem0,size=1G id=mem1,size=1G id=mem2,size=1G
--numa guest_numa_id=0,memory_zones=[mem0,mem2] guest_numa_id=1,memory_zones=mem1
--memory-zone id=mem0,size=1G id=mem1,size=1G --memory-zone id=mem2,size=1G
--numa guest_numa_id=0,memory_zones=[mem0,mem2] --numa guest_numa_id=1,memory_zones=mem1
```
### `sgx_epc_sections`
@@ -570,7 +570,7 @@ _Example_
```
--sgx-epc id=epc0,size=32M id=epc1,size=64M id=epc2,size=32M
--numa guest_numa_id=0,sgx_epc_sections=epc1 guest_numa_id=1,sgx_epc_sections=[epc0,epc2]
--numa guest_numa_id=0,sgx_epc_sections=epc1 --numa guest_numa_id=1,sgx_epc_sections=[epc0,epc2]
```
### PCI bus

View File

@@ -4,20 +4,12 @@
## Building a suitable binary
Modify the `Cargo.toml` file to add `debug = 1` to the `[profile.release]` block. It should look like this:
```
[profile.release]
lto = true
debug = 1
```
This adds the symbol information to the release binary but does not otherwise affect the performance.
The binary must also be built with frame pointers included so that the call graph can be captured by the profiler.
```
$ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --release
$ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --profile profiling
```
## Profiling
@@ -27,13 +19,13 @@ $ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --release
e.g.
```
$ perf record -g target/release/cloud-hypervisor \
$ perf record -g target/profiling/cloud-hypervisor \
--kernel ~/src/linux/vmlinux \
--pmem file=~/workloads/focal.raw \
--cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \
--api-socket=/tmp/api1
--api-socket /tmp/api1
```
For analysing the samples:
@@ -60,5 +52,5 @@ $ perf record --call-graph lbr --all-user --user-callchains -g target/release/cl
--cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \
--api-socket=/tmp/api1
--api-socket /tmp/api1
```

View File

@@ -25,14 +25,14 @@ First thing, we must run a Cloud Hypervisor VM:
At any point in time when the VM is running, one might choose to pause it:
```bash
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock pause
./ch-remote --api-socket /tmp/cloud-hypervisor.sock pause
```
Once paused, the VM can be safely snapshot into the specified directory and
using the following command:
```bash
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock snapshot file:///home/foo/snapshot
./ch-remote --api-socket /tmp/cloud-hypervisor.sock snapshot file:///home/foo/snapshot
```
Given the directory was present on the system, the snapshot will succeed and
@@ -79,7 +79,7 @@ Or using two different commands from two terminals:
./cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock
# Second terminal
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock restore source_url=file:///home/foo/snapshot
./ch-remote --api-socket /tmp/cloud-hypervisor.sock restore source_url=file:///home/foo/snapshot
```
Remember the VM is restored in a `paused` state, which was the VM's state when
@@ -87,7 +87,7 @@ it was snapshot. For this reason, one must explicitly `resume` the VM before to
start using it.
```bash
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock resume
./ch-remote --api-socket /tmp/cloud-hypervisor.sock resume
```
At this point, the VM is fully restored and is identical to the VM which was

View File

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

View File

@@ -94,7 +94,7 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
--memory size=1024M,hugepages=on,shared=true \
--kernel linux/arch/x86/boot/compressed/vmlinux.bin \
--cmdline "console=ttyS0 root=/dev/vda1 rw iommu=off" \
--disk path=images/focal-server-cloudimg-amd64.raw vhost_user=true,socket=/var/tmp/vhost.1,num_queues=4,queue_size=128 \
--disk path=images/focal-server-cloudimg-amd64.raw --disk vhost_user=true,socket=/var/tmp/vhost.1,num_queues=4,queue_size=128 \
--console off \
--serial tty \
--rng

View File

@@ -5,7 +5,6 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
libc = "0.2.138"
once_cell = "1.16.0"
serde = { version = "1.0.150", features = ["rc", "derive"] }
serde_json = "1.0.89"
libc = "0.2.139"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: Apache-2.0
//
use once_cell::sync::OnceCell;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::HashMap;
@@ -12,14 +11,15 @@ use std::io::Write;
use std::os::unix::io::AsRawFd;
use std::time::{Duration, Instant};
static MONITOR: OnceCell<(File, Instant)> = OnceCell::new();
static mut MONITOR: Option<(File, Instant)> = None;
/// This function must only be called once from the main process before any threads
/// are created to avoid race conditions
pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
// There is only one caller of this function, so MONITOR is written to only once
assert!(MONITOR.get().is_none());
// SAFETY: there is only one caller of this function, so MONITOR is written to only once
assert!(unsafe { MONITOR.is_none() });
let fd = file.as_raw_fd();
// SAFETY: FFI call to configure the fd
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
@@ -28,9 +28,10 @@ pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
MONITOR.get_or_init(|| (file, Instant::now()));
// SAFETY: MONITOR is None. Nobody else can hold a reference to it.
unsafe {
MONITOR = Some((file, Instant::now()));
};
Ok(())
}
@@ -43,7 +44,8 @@ struct Event<'a> {
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
if let Some((file, start)) = MONITOR.get().as_ref() {
// SAFETY: MONITOR is always in a valid state (None or Some).
if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
let e = Event {
timestamp: start.elapsed(),
source,

465
fuzz/Cargo.lock generated
View File

@@ -5,15 +5,16 @@ version = 3
[[package]]
name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#4fd38dd5f746730ec5ae848dafcf8c2f50a13fc3"
dependencies = [
"vm-memory",
]
[[package]]
name = "anyhow"
version = "1.0.66"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "api_client"
@@ -24,15 +25,15 @@ dependencies = [
[[package]]
name = "arbitrary"
version = "1.2.0"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880"
checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad"
[[package]]
name = "arc-swap"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
name = "arch"
@@ -56,6 +57,34 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "argh"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
dependencies = [
"argh_derive",
"argh_shared",
]
[[package]]
name = "argh_derive"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "argh_shared"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
[[package]]
name = "bincode"
version = "1.3.3"
@@ -71,12 +100,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "block_util"
version = "0.1.0"
@@ -85,11 +108,12 @@ dependencies = [
"libc",
"log",
"qcow",
"smallvec",
"thiserror",
"versionize",
"versionize_derive",
"vhdx",
"virtio-bindings",
"virtio-bindings 0.2.0",
"virtio-queue",
"vm-memory",
"vm-virtio",
@@ -104,9 +128,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.77"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [
"jobserver",
]
@@ -117,37 +141,13 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
dependencies = [
"bitflags 1.3.2",
"clap_lex",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
"terminal_size",
]
[[package]]
name = "clap_lex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cloud-hypervisor"
version = "28.3.0"
version = "29.0.0"
dependencies = [
"anyhow",
"api_client",
"clap",
"argh",
"epoll",
"event_monitor",
"hypervisor",
@@ -175,7 +175,9 @@ dependencies = [
"epoll",
"libc",
"libfuzzer-sys",
"linux-loader",
"micro_http",
"net_util",
"once_cell",
"qcow",
"seccompiler",
@@ -206,9 +208,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]]
name = "darling"
version = "0.14.2"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
dependencies = [
"darling_core",
"darling_macro",
@@ -216,9 +218,9 @@ dependencies = [
[[package]]
name = "darling_core"
version = "0.14.2"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [
"fnv",
"ident_case",
@@ -230,9 +232,9 @@ dependencies = [
[[package]]
name = "darling_macro"
version = "0.14.2"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [
"darling_core",
"quote",
@@ -246,12 +248,11 @@ dependencies = [
"acpi_tables",
"anyhow",
"arch",
"bitflags 2.4.1",
"bitflags",
"byteorder",
"hypervisor",
"libc",
"log",
"phf",
"thiserror",
"tpm",
"versionize",
@@ -268,28 +269,7 @@ version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"bitflags",
"libc",
]
@@ -298,16 +278,15 @@ name = "event_monitor"
version = "0.1.0"
dependencies = [
"libc",
"once_cell",
"serde",
"serde_json",
]
[[package]]
name = "fdt"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "964f5becd44d069dca0beea2b4bc05639ae7bf3b3f5369c295aff360bb57cca2"
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "fnv"
@@ -326,15 +305,6 @@ dependencies = [
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "hypervisor"
version = "0.1.0"
@@ -356,12 +326,11 @@ dependencies = [
[[package]]
name = "iced-x86"
version = "1.17.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec"
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [
"lazy_static",
"static_assertions",
]
[[package]]
@@ -370,43 +339,21 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "io-lifetimes"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "io-uring"
version = "0.5.9"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba34abb5175052fc1a2227a10d2275b7386c9990167de9786c0b88d8b062330"
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"libc",
]
[[package]]
name = "is-terminal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jobserver"
@@ -446,15 +393,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.138"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libfuzzer-sys"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8fff891139ee62800da71b7fd5b508d570b9ad95e614a53c6f453ca08366038"
checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e"
dependencies = [
"arbitrary",
"cc",
@@ -470,12 +417,6 @@ dependencies = [
"vm-memory",
]
[[package]]
name = "linux-raw-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
[[package]]
name = "log"
version = "0.4.17"
@@ -488,7 +429,7 @@ dependencies = [
[[package]]
name = "micro_http"
version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4b18a043e997da5b5f679e3defc279fec908753e"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#b538bf89e50be83b6fa9ab1896727ff61e02fa13"
dependencies = [
"libc",
"vmm-sys-util",
@@ -515,7 +456,7 @@ dependencies = [
"thiserror",
"versionize",
"versionize_derive",
"virtio-bindings",
"virtio-bindings 0.2.0",
"virtio-queue",
"vm-memory",
"vm-virtio",
@@ -524,20 +465,14 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.16.0"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "option_parser"
version = "0.1.0"
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "pci"
version = "0.1.0"
@@ -561,53 +496,11 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "phf"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
dependencies = [
"phf_macros",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
dependencies = [
"siphasher",
]
[[package]]
name = "proc-macro2"
version = "1.0.76"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@@ -625,28 +518,13 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rate_limiter"
version = "0.1.0"
@@ -658,9 +536,9 @@ dependencies = [
[[package]]
name = "remain"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a81bc6a3aaeb180f767bd2bda8c03bac5b93b3b69a783c66f35d16a4df276cf"
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
dependencies = [
"proc-macro2",
"quote",
@@ -676,25 +554,11 @@ dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "seccompiler"
@@ -707,24 +571,24 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.14"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.150"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.150"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -733,9 +597,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.89"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa",
"ryu",
@@ -744,9 +608,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
dependencies = [
"serde",
"serde_with_macros",
@@ -754,9 +618,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [
"darling",
"proc-macro2",
@@ -770,9 +634,9 @@ version = "0.1.0"
[[package]]
name = "signal-hook"
version = "0.3.14"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
dependencies = [
"libc",
"signal-hook-registry",
@@ -780,24 +644,18 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "siphasher"
version = "0.3.10"
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "strsim"
@@ -807,48 +665,29 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.105"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys",
]
[[package]]
name = "thiserror"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -863,6 +702,7 @@ dependencies = [
"byteorder",
"libc",
"log",
"net_gen",
"thiserror",
"vmm-sys-util",
]
@@ -880,15 +720,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "uuid"
version = "1.2.2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [
"getrandom",
]
@@ -947,7 +787,9 @@ dependencies = [
[[package]]
name = "vfio_user"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#afbbd5722885e961ce12baea12efe01d52ce14b0"
dependencies = [
"bitflags",
"libc",
"log",
"serde",
@@ -978,7 +820,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"libc",
"vm-memory",
"vmm-sys-util",
@@ -990,6 +832,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
[[package]]
name = "virtio-bindings"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9084faf91b9aa9676ae2cac8f1432df2839d9566e6f19f29dbc13a8b831dff"
[[package]]
name = "virtio-devices"
version = "0.1.0"
@@ -1015,7 +863,7 @@ dependencies = [
"versionize",
"versionize_derive",
"vhost",
"virtio-bindings",
"virtio-bindings 0.2.0",
"virtio-queue",
"vm-allocator",
"vm-device",
@@ -1027,12 +875,12 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
checksum = "3ba81e2bcc21c0d2fc5e6683e79367e26ad219197423a498df801d79d5ba77bd"
dependencies = [
"log",
"virtio-bindings",
"virtio-bindings 0.1.0",
"vm-memory",
"vmm-sys-util",
]
@@ -1105,9 +953,8 @@ dependencies = [
"anyhow",
"arc-swap",
"arch",
"bitflags 2.4.1",
"bitflags",
"block_util",
"clap",
"devices",
"epoll",
"event_monitor",
@@ -1146,11 +993,11 @@ dependencies = [
[[package]]
name = "vmm-sys-util"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc06a16ee8ebf0d9269aed304030b0d20a866b8b3dd3d4ce532596ac567a0d24"
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"libc",
"serde",
"serde_derive",
@@ -1178,74 +1025,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"

View File

@@ -12,17 +12,19 @@ cargo-fuzz = true
block_util = { path = "../block_util" }
devices = { path = "../devices" }
epoll = "4.3.1"
libc = "0.2.135"
libfuzzer-sys = "0.4.5"
libc = "0.2.138"
libfuzzer-sys = "0.4.6"
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
once_cell = "1.16.0"
net_util = { path = "../net_util" }
once_cell = "1.17.1"
qcow = { path = "../qcow" }
seccompiler = "0.3.0"
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.7.0"
virtio-queue = "0.7.1"
vmm = { path = "../vmm" }
vmm-sys-util = "0.11.0"
vmm-sys-util = "0.11.1"
vm-memory = "0.10.0"
vm-device = { path = "../vm-device" }
vm-virtio = { path = "../vm-virtio" }
@@ -74,12 +76,30 @@ path = "fuzz_targets/iommu.rs"
test = false
doc = false
[[bin]]
name = "linux_loader"
path = "fuzz_targets/linux_loader.rs"
test = false
doc = false
[[bin]]
name = "linux_loader_cmdline"
path = "fuzz_targets/linux_loader_cmdline.rs"
test = false
doc = false
[[bin]]
name = "mem"
path = "fuzz_targets/mem.rs"
test = false
doc = false
[[bin]]
name = "net"
path = "fuzz_targets/net.rs"
test = false
doc = false
[[bin]]
name = "pmem"
path = "fuzz_targets/pmem.rs"

View File

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

View File

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

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

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

View File

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

View File

@@ -11,23 +11,23 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = []
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.69"
byteorder = "1.4.3"
thiserror = "1.0.37"
libc = "0.2.138"
thiserror = "1.0.38"
libc = "0.2.139"
log = "0.4.17"
kvm-ioctls = { version = "0.13.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.150", features = ["rc", "derive"] }
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
version = "1.17.0"
version = "1.18.0"
default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]

View File

@@ -18,8 +18,8 @@ fn get_op<T: CpuStateManager>(
insn: &Instruction,
op_index: u32,
op_size: usize,
state: &T,
platform: &dyn PlatformEmulator<CpuState = T>,
state: &mut T,
platform: &mut dyn PlatformEmulator<CpuState = T>,
) -> Result<u64, PlatformError> {
if insn.op_count() < op_index + 1 {
return Err(PlatformError::InvalidOperand(anyhow!(

View File

@@ -15,73 +15,89 @@ use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::regs::DF;
use crate::arch::x86::Exception;
macro_rules! movs {
($bound:ty) => {
fn emulate(
&self,
insn: &Instruction,
state: &mut T,
platform: &mut dyn PlatformEmulator<CpuState = T>,
) -> Result<(), EmulationError<Exception>> {
let mut count: u64 = if insn.has_rep_prefix() {
state
.read_reg(Register::ECX)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
} else {
1
};
let mut rsi = state
.read_reg(Register::RSI)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
let mut rdi = state
.read_reg(Register::RDI)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
let df = (state.flags() & DF) != 0;
let len = std::mem::size_of::<$bound>();
while count > 0 {
let mut memory: [u8; 4] = [0; 4];
let src = state
.linearize(Register::DS, rsi, false)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
let dst = state
.linearize(Register::ES, rdi, true)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
platform
.read_memory(src, &mut memory[0..len])
.map_err(EmulationError::PlatformEmulationError)?;
platform
.write_memory(dst, &memory[0..len])
.map_err(EmulationError::PlatformEmulationError)?;
if df {
rsi = rsi.wrapping_sub(len as u64);
rdi = rdi.wrapping_sub(len as u64);
} else {
rsi = rsi.wrapping_add(len as u64);
rdi = rdi.wrapping_add(len as u64);
}
count -= 1;
}
state
.write_reg(Register::RSI, rsi)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
state
.write_reg(Register::RDI, rdi)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
if insn.has_rep_prefix() {
state
.write_reg(Register::ECX, 0)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
}
Ok(())
}
};
}
pub struct Movsd_m32_m32;
impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
fn emulate(
&self,
insn: &Instruction,
state: &mut T,
platform: &mut dyn PlatformEmulator<CpuState = T>,
) -> Result<(), EmulationError<Exception>> {
let mut count: u64 = if insn.has_rep_prefix() {
state
.read_reg(Register::ECX)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
} else {
1
};
movs!(u32);
}
let mut rsi = state
.read_reg(Register::RSI)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
let mut rdi = state
.read_reg(Register::RDI)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
pub struct Movsw_m16_m16;
impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 {
movs!(u16);
}
let df = (state.flags() & DF) != 0;
let len = std::mem::size_of::<u32>();
while count > 0 {
let mut memory: [u8; 4] = [0; 4];
let src = state
.linearize(Register::DS, rsi, false)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
let dst = state
.linearize(Register::ES, rdi, true)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
platform
.read_memory(src, &mut memory[0..len])
.map_err(EmulationError::PlatformEmulationError)?;
platform
.write_memory(dst, &memory[0..len])
.map_err(EmulationError::PlatformEmulationError)?;
if df {
rsi = rsi.wrapping_sub(len as u64);
rdi = rdi.wrapping_sub(len as u64);
} else {
rsi = rsi.wrapping_add(len as u64);
rdi = rdi.wrapping_add(len as u64);
}
count -= 1;
}
state
.write_reg(Register::RSI, rsi)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
state
.write_reg(Register::RDI, rdi)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
if insn.has_rep_prefix() {
state
.write_reg(Register::ECX, 0)
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
}
Ok(())
}
pub struct Movsb_m8_m8;
impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
movs!(u8);
}
#[cfg(test)]
@@ -142,4 +158,127 @@ mod tests {
vmm.read_memory(0x8 + 8, &mut data).unwrap();
assert_eq!(0x0, <u32>::from_le_bytes(data));
}
#[test]
fn test_rep_movsw_m16_m16() {
let ip: u64 = 0x1000;
let memory: [u8; 24] = [
0x78, 0x56, 0x34, 0x12, // 0x12345678
0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
0x00, 0x00, 0x00, 0x00, // 0x00000000
0x00, 0x00, 0x00, 0x00, // 0x00000000
0x00, 0x00, 0x00, 0x00, // 0x00000000
];
let insn = [0x66, 0xf3, 0xa5]; // rep movsw
let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)];
let mut data = [0u8; 2];
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
vmm.read_memory(0xc, &mut data).unwrap();
assert_eq!(0x5678, <u16>::from_le_bytes(data));
vmm.read_memory(0xc + 2, &mut data).unwrap();
assert_eq!(0x1234, <u16>::from_le_bytes(data));
vmm.read_memory(0xc + 4, &mut data).unwrap();
assert_eq!(0xccdd, <u16>::from_le_bytes(data));
vmm.read_memory(0xc + 6, &mut data).unwrap();
assert_eq!(0xaabb, <u16>::from_le_bytes(data));
vmm.read_memory(0xc + 8, &mut data).unwrap();
assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
vmm.read_memory(0xc + 10, &mut data).unwrap();
assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
// The rest should be default value 0 from MockVmm
vmm.read_memory(0xc + 12, &mut data).unwrap();
assert_eq!(0x0, <u16>::from_le_bytes(data));
}
#[test]
fn test_movsw_m16_m16() {
let ip: u64 = 0x1000;
let memory: [u8; 4] = [
0x78, 0x56, 0x34, 0x12, // 0x12345678
];
let insn = [0x66, 0xa5]; // movsw
let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
let mut data = [0u8; 2];
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
vmm.read_memory(0x8, &mut data).unwrap();
assert_eq!(0x5678, <u16>::from_le_bytes(data));
// Only two bytes were copied, so the value at 0xa should be zero
vmm.read_memory(0xa, &mut data).unwrap();
assert_eq!(0x0, <u16>::from_le_bytes(data));
// The rest should be default value 0 from MockVmm
vmm.read_memory(0x4, &mut data).unwrap();
assert_eq!(0x0, <u16>::from_le_bytes(data));
vmm.read_memory(0x8 + 8, &mut data).unwrap();
assert_eq!(0x0, <u16>::from_le_bytes(data));
}
#[test]
fn test_movsb_m8_m8() {
let ip: u64 = 0x1000;
let memory: [u8; 4] = [
0x78, 0x56, 0x34, 0x12, // 0x12345678
];
let insn = [0x66, 0xa4]; // movsb
let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
let mut data = [0u8; 1];
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
vmm.read_memory(0x8, &mut data).unwrap();
assert_eq!(0x78, data[0]);
// Only one byte was copied, so the value at 0x9 should be zero
vmm.read_memory(0x9, &mut data).unwrap();
assert_eq!(0x0, data[0]);
// The rest should be default value 0 from MockVmm
vmm.read_memory(0x4, &mut data).unwrap();
assert_eq!(0x0, data[0]);
// the src value is left as is after movb
vmm.read_memory(0x0, &mut data).unwrap();
assert_eq!(0x78, data[0]);
}
#[test]
fn test_rep_movsb_m8_m8() {
let ip: u64 = 0x1000;
let memory: [u8; 16] = [
0x78, 0x56, 0x34, 0x12, // 0x12345678
0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb
0x00, 0x00, 0x00, 0x00, // 0x00000000
0x00, 0x00, 0x00, 0x00, // 0x00000000
];
let insn = [0x66, 0xf3, 0xa4]; // rep movsw
let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)];
let mut data = [0u8; 1];
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
vmm.read_memory(0x8, &mut data).unwrap();
assert_eq!(0x78, data[0]);
vmm.read_memory(0x8 + 1, &mut data).unwrap();
assert_eq!(0x56, data[0]);
vmm.read_memory(0x8 + 2, &mut data).unwrap();
assert_eq!(0x34, data[0]);
vmm.read_memory(0x8 + 3, &mut data).unwrap();
assert_eq!(0x12, data[0]);
vmm.read_memory(0x8 + 4, &mut data).unwrap();
assert_eq!(0xbb, data[0]);
vmm.read_memory(0x8 + 5, &mut data).unwrap();
assert_eq!(0xaa, data[0]);
// The rest should be default value 0 from MockVmm
vmm.read_memory(0x8 + 6, &mut data).unwrap();
assert_eq!(0x0, data[0]);
}
}

View File

@@ -526,6 +526,8 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
(mov, Movzx_r64_rm16),
// MOVS
(movs, Movsd_m32_m32),
(movs, Movsw_m16_m16),
(movs, Movsb_m8_m8),
// OR
(or, Or_rm8_r8)
);

View File

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

View File

@@ -108,7 +108,7 @@ pub trait Hypervisor: Send + Sync {
///
/// Get the supported CpuID
///
fn get_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
fn get_supported_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
///
/// Check particular extensions if any
///

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ use crate::vec_with_array_field;
use crate::vm::{self, InterruptSourceConfig, VmOps};
use crate::HypervisorType;
#[cfg(target_arch = "aarch64")]
use crate::{arm64_core_reg_id, offset__of};
use crate::{arm64_core_reg_id, offset_of};
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
use std::any::Any;
use std::collections::HashMap;
@@ -106,7 +106,7 @@ pub use {
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
#[cfg(feature = "tdx")]
const KVM_EXIT_TDX: u32 = 35;
const KVM_EXIT_TDX: u32 = 50;
#[cfg(feature = "tdx")]
const TDG_VP_VMCALL_GET_QUOTE: u64 = 0x10002;
#[cfg(feature = "tdx")]
@@ -746,36 +746,34 @@ impl vm::Vm for KvmVm {
///
#[cfg(feature = "tdx")]
fn tdx_init(&self, cpuid: &[CpuIdEntry], max_vcpus: u32) -> vm::Result<()> {
use std::io::{Error, ErrorKind};
let cpuid: Vec<kvm_bindings::kvm_cpuid_entry2> =
const TDX_ATTR_SEPT_VE_DISABLE: usize = 28;
let mut cpuid: Vec<kvm_bindings::kvm_cpuid_entry2> =
cpuid.iter().map(|e| (*e).into()).collect();
let kvm_cpuid = kvm_bindings::CpuId::from_entries(&cpuid).map_err(|_| {
vm::HypervisorVmError::InitializeTdx(Error::new(
ErrorKind::Other,
"failed to allocate CpuId",
))
})?;
cpuid.resize(256, kvm_bindings::kvm_cpuid_entry2::default());
#[repr(C)]
struct TdxInitVm {
max_vcpus: u32,
tsc_khz: u32,
attributes: u64,
cpuid: u64,
max_vcpus: u32,
padding: u32,
mrconfigid: [u64; 6],
mrowner: [u64; 6],
mrownerconfig: [u64; 6],
reserved: [u64; 43],
cpuid_nent: u32,
cpuid_padding: u32,
cpuid_entries: [kvm_bindings::kvm_cpuid_entry2; 256],
}
let data = TdxInitVm {
attributes: 1 << TDX_ATTR_SEPT_VE_DISABLE,
max_vcpus,
tsc_khz: 0,
attributes: 0,
cpuid: kvm_cpuid.as_fam_struct_ptr() as u64,
padding: 0,
mrconfigid: [0; 6],
mrowner: [0; 6],
mrownerconfig: [0; 6],
reserved: [0; 43],
cpuid_nent: cpuid.len() as u32,
cpuid_padding: 0,
cpuid_entries: cpuid.as_slice().try_into().unwrap(),
};
tdx_command(
@@ -837,19 +835,23 @@ impl vm::Vm for KvmVm {
fn tdx_command(
fd: &RawFd,
command: TdxCommand,
metadata: u32,
flags: u32,
data: u64,
) -> std::result::Result<(), std::io::Error> {
#[repr(C)]
struct TdxIoctlCmd {
command: TdxCommand,
metadata: u32,
flags: u32,
data: u64,
error: u64,
unused: u64,
}
let cmd = TdxIoctlCmd {
command,
metadata,
flags,
data,
error: 0,
unused: 0,
};
// SAFETY: FFI call. All input parameters are valid.
let ret = unsafe {
@@ -1021,7 +1023,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
///
/// X86 specific call to get the system supported CPUID values.
///
fn get_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
let kvm_cpuid = self
.kvm
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
@@ -1114,7 +1116,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "aarch64")]
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
let mut state: StandardRegisters = kvm_regs::default();
let mut off = offset__of!(user_pt_regs, regs);
let mut off = offset_of!(user_pt_regs, regs);
// There are 31 user_pt_regs:
// https://elixir.free-electrons.com/linux/v4.14.174/source/arch/arm64/include/uapi/asm/ptrace.h#L72
// These actually are the general-purpose registers of the Armv8-a
@@ -1131,7 +1133,7 @@ impl cpu::Vcpu for KvmVcpu {
// We are now entering the "Other register" section of the ARMv8-a architecture.
// First one, stack pointer.
let off = offset__of!(user_pt_regs, sp);
let off = offset_of!(user_pt_regs, sp);
state.regs.sp = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1140,7 +1142,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Second one, the program counter.
let off = offset__of!(user_pt_regs, pc);
let off = offset_of!(user_pt_regs, pc);
state.regs.pc = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1149,7 +1151,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Next is the processor state.
let off = offset__of!(user_pt_regs, pstate);
let off = offset_of!(user_pt_regs, pstate);
state.regs.pstate = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1158,7 +1160,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// The stack pointer associated with EL1
let off = offset__of!(kvm_regs, sp_el1);
let off = offset_of!(kvm_regs, sp_el1);
state.sp_el1 = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1168,7 +1170,7 @@ impl cpu::Vcpu for KvmVcpu {
// Exception Link Register for EL1, when taking an exception to EL1, this register
// holds the address to which to return afterwards.
let off = offset__of!(kvm_regs, elr_el1);
let off = offset_of!(kvm_regs, elr_el1);
state.elr_el1 = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1177,7 +1179,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Saved Program Status Registers, there are 5 of them used in the kernel.
let mut off = offset__of!(kvm_regs, spsr);
let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize {
state.spsr[i] = self
.fd
@@ -1190,7 +1192,7 @@ impl cpu::Vcpu for KvmVcpu {
// Now moving on to floting point registers which are stored in the user_fpsimd_state in the kernel:
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 {
state.fp_regs.vregs[i] = self
.fd
@@ -1200,7 +1202,7 @@ impl cpu::Vcpu for KvmVcpu {
}
// Floating-point Status Register
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpsr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
state.fp_regs.fpsr = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
@@ -1209,7 +1211,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Floating-point Control Register
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpcr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
state.fp_regs.fpcr = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
@@ -1238,7 +1240,7 @@ impl cpu::Vcpu for KvmVcpu {
fn set_regs(&self, state: &StandardRegisters) -> cpu::Result<()> {
// The function follows the exact identical order from `state`. Look there
// for some additional info on registers.
let mut off = offset__of!(user_pt_regs, regs);
let mut off = offset_of!(user_pt_regs, regs);
for i in 0..31 {
self.fd
.set_one_reg(
@@ -1249,7 +1251,7 @@ impl cpu::Vcpu for KvmVcpu {
off += std::mem::size_of::<u64>();
}
let off = offset__of!(user_pt_regs, sp);
let off = offset_of!(user_pt_regs, sp);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1257,7 +1259,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(user_pt_regs, pc);
let off = offset_of!(user_pt_regs, pc);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1265,7 +1267,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(user_pt_regs, pstate);
let off = offset_of!(user_pt_regs, pstate);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1273,7 +1275,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, sp_el1);
let off = offset_of!(kvm_regs, sp_el1);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1281,7 +1283,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, elr_el1);
let off = offset_of!(kvm_regs, elr_el1);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1289,7 +1291,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let mut off = offset__of!(kvm_regs, spsr);
let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize {
self.fd
.set_one_reg(
@@ -1300,7 +1302,7 @@ impl cpu::Vcpu for KvmVcpu {
off += std::mem::size_of::<u64>();
}
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 {
self.fd
.set_one_reg(
@@ -1311,7 +1313,7 @@ impl cpu::Vcpu for KvmVcpu {
off += mem::size_of::<u128>();
}
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpsr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
@@ -1319,7 +1321,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpcr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
@@ -1700,8 +1702,8 @@ impl cpu::Vcpu for KvmVcpu {
// it to the corresponding KVM ID, and call `KVM_GET_ONE_REG` API to
// get the value of the system parameter.
//
let id: u64 = KVM_REG_ARM64 as u64
| KVM_REG_SIZE_U64 as u64
let id: u64 = KVM_REG_ARM64
| KVM_REG_SIZE_U64
| KVM_REG_ARM64_SYSREG as u64
| ((((sys_reg) >> 5)
& (KVM_REG_ARM64_SYSREG_OP0_MASK
@@ -1733,10 +1735,10 @@ impl cpu::Vcpu for KvmVcpu {
const PSTATE_FAULT_BITS_64: u64 =
PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
let kreg_off = offset__of!(kvm_regs, regs);
let kreg_off = offset_of!(kvm_regs, regs);
// Get the register index of the PSTATE (Processor State) register.
let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
@@ -1747,7 +1749,7 @@ impl cpu::Vcpu for KvmVcpu {
// Other vCPUs are powered off initially awaiting PSCI wakeup.
if cpu_id == 0 {
// Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset__of!(user_pt_regs, pc) + kreg_off;
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
self.fd
.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip.into())
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1756,7 +1758,7 @@ impl cpu::Vcpu for KvmVcpu {
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
@@ -2066,6 +2068,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(feature = "tdx")]
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
@@ -2089,6 +2092,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(feature = "tdx")]
fn set_tdx_status(&mut self, status: TdxExitStatus) {
let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
tdx_vmcall.status_code = match status {

View File

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

View File

@@ -38,7 +38,9 @@ use std::fs::File;
use std::os::unix::io::AsRawFd;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry};
use crate::arch::x86::{
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
};
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
@@ -268,7 +270,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
///
/// Get the supported CpuID
///
fn get_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
Ok(Vec::new())
}
}
@@ -297,7 +299,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Returns the vCPU general purpose registers.
///
fn get_regs(&self) -> cpu::Result<crate::arch::x86::StandardRegisters> {
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
Ok(self
.fd
.get_regs()
@@ -308,7 +310,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Sets the vCPU general purpose registers.
///
fn set_regs(&self, regs: &crate::arch::x86::StandardRegisters) -> cpu::Result<()> {
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
let regs = (*regs).into();
self.fd
.set_regs(&regs)
@@ -318,7 +320,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Returns the vCPU special registers.
///
fn get_sregs(&self) -> cpu::Result<crate::arch::x86::SpecialRegisters> {
fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
Ok(self
.fd
.get_sregs()
@@ -329,7 +331,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Sets the vCPU special registers.
///
fn set_sregs(&self, sregs: &crate::arch::x86::SpecialRegisters) -> cpu::Result<()> {
fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
let sregs = (*sregs).into();
self.fd
.set_sregs(&sregs)
@@ -444,10 +446,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name::HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -456,12 +458,13 @@ impl cpu::Vcpu for MshvVcpu {
_ => {}
}
// SAFETY: access_info is valid, otherwise we won't be here
assert!(
// SAFETY: access_info is valid, otherwise we won't be here
(unsafe { access_info.__bindgen_anon_1.string_op() } != 1),
"String IN/OUT not supported"
);
assert!(
// SAFETY: access_info is valid, otherwise we won't be here
(unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1),
"Rep IN/OUT not supported"
);
@@ -492,10 +495,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name::HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -579,7 +582,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn get_lapic(&self) -> cpu::Result<crate::arch::x86::LapicState> {
fn get_lapic(&self) -> cpu::Result<LapicState> {
Ok(self
.fd
.get_lapic()
@@ -590,7 +593,7 @@ impl cpu::Vcpu for MshvVcpu {
///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
///
fn set_lapic(&self, lapic: &crate::arch::x86::LapicState) -> cpu::Result<()> {
fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> {
let lapic: mshv_bindings::LapicState = (*lapic).clone().into();
self.fd
.set_lapic(&lapic)

View File

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

View File

@@ -28,12 +28,10 @@ pub mod inn;
// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
// --constified-enum '*' --with-derive-default
pub mod sockios;
pub use if_tun::{
sock_fprog, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TAP, IFF_VNET_HDR, TUN_F_CSUM, TUN_F_TSO4,
TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO,
};
pub use iff::{ifreq, net_device_flags_IFF_UP, setsockopt, sockaddr, AF_INET};
pub use inn::sockaddr_in;
pub use if_tun::*;
pub use iff::*;
pub use inn::*;
pub use sockios::*;
pub const TUNTAP: ::std::os::raw::c_uint = 84;

View File

@@ -7,22 +7,22 @@ edition = "2021"
[dependencies]
epoll = "4.3.1"
getrandom = "0.2.8"
libc = "0.2.138"
libc = "0.2.139"
log = "0.4.17"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
serde = "1.0.150"
thiserror = "1.0.37"
serde = "1.0.151"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
virtio-bindings = "0.1.0"
virtio-bindings = "0.2.0"
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0"
[dev-dependencies]
once_cell = "1.16.0"
pnet = "0.34.0"
pnet_datalink = "0.34.0"
serde_json = "1.0.89"
once_cell = "1.17.1"
pnet = "0.33.0"
pnet_datalink = "0.33.0"
serde_json = "1.0.93"

View File

@@ -6,7 +6,7 @@ use crate::GuestMemoryMmap;
use crate::Tap;
use libc::c_uint;
use std::sync::Arc;
use virtio_bindings::bindings::virtio_net::{
use virtio_bindings::virtio_net::{
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_F_GUEST_CSUM,

View File

@@ -21,7 +21,7 @@ use std::{io, mem, net};
use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use virtio_bindings::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_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4,
VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MQ,
@@ -66,32 +66,34 @@ fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_gen::sockaddr {
let addr_in = net_gen::sockaddr_in {
sin_family: net_gen::AF_INET as u16,
sin_port: 0,
// SAFETY: ip_addr can be safely transmute to in_addr
sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
__pad: [0; 8usize],
};
// SAFETY: addr_in can be safely transmute to sockaddr
unsafe { mem::transmute(addr_in) }
}
fn create_inet_socket() -> Result<net::UdpSocket> {
// This is safe since we check the return value.
// SAFETY: we check the return value.
let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
if sock < 0 {
return Err(Error::CreateSocket(IoError::last_os_error()));
}
// This is safe; nothing else will use or hold onto the raw sock fd.
// SAFETY: nothing else will use or hold onto the raw sock fd.
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}
fn create_unix_socket() -> Result<net::UdpSocket> {
// This is safe since we check the return value.
// SAFETY: we check the return value.
let sock = unsafe { libc::socket(libc::AF_UNIX, libc::SOCK_DGRAM, 0) };
if sock < 0 {
return Err(Error::CreateSocket(IoError::last_os_error()));
}
// This is safe; nothing else will use or hold onto the raw sock fd.
// SAFETY: nothing else will use or hold onto the raw sock fd.
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}

View File

@@ -83,10 +83,11 @@ impl TxVirtio {
}
let len = if !iovecs.is_empty() {
// SAFETY: FFI call with correct arguments
let result = unsafe {
libc::writev(
tap.as_raw_fd() as libc::c_int,
iovecs.as_ptr(),
iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int,
)
};
@@ -221,10 +222,11 @@ impl RxVirtio {
}
let len = if !iovecs.is_empty() {
// SAFETY: FFI call with correct arguments
let result = unsafe {
libc::readv(
tap.as_raw_fd() as libc::c_int,
iovecs.as_ptr(),
iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int,
)
};

View File

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

View File

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

View File

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

View File

@@ -32,6 +32,8 @@ const CAPABILITY_MAX_OFFSET: usize = 192;
const INTERRUPT_LINE_PIN_REG: usize = 15;
pub const PCI_CONFIGURATION_ID: &str = "pci_configuration";
/// Represents the types of PCI headers allowed in the configuration registers.
#[derive(Copy, Clone)]
pub enum PciHeaderType {
@@ -394,7 +396,7 @@ fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
None
}
#[derive(Default, Clone, Copy, Versionize)]
#[derive(Debug, Default, Clone, Copy, Versionize)]
struct PciBar {
addr: u32,
size: u32,
@@ -403,7 +405,7 @@ struct PciBar {
}
#[derive(Versionize)]
struct PciConfigurationState {
pub struct PciConfigurationState {
registers: Vec<u32>,
writable_bits: Vec<u32>,
bars: Vec<PciBar>,
@@ -553,46 +555,78 @@ impl PciConfiguration {
subsystem_vendor_id: u16,
subsystem_id: u16,
msix_config: Option<Arc<Mutex<MsixConfig>>>,
state: Option<PciConfigurationState>,
) -> Self {
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
// TODO(dverkamp): Status should be write-1-to-clear
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
let pi = if let Some(pi) = programming_interface {
pi.get_register_value()
let (
registers,
writable_bits,
bars,
rom_bar_addr,
rom_bar_size,
rom_bar_used,
last_capability,
msix_cap_reg_idx,
) = if let Some(state) = state {
(
state.registers.try_into().unwrap(),
state.writable_bits.try_into().unwrap(),
state.bars.try_into().unwrap(),
state.rom_bar_addr,
state.rom_bar_size,
state.rom_bar_used,
state.last_capability,
state.msix_cap_reg_idx,
)
} else {
0
};
registers[2] = u32::from(class_code.get_register_value()) << 24
| u32::from(subclass.get_register_value()) << 16
| u32::from(pi) << 8
| u32::from(revision_id);
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
match header_type {
PciHeaderType::Device => {
registers[3] = 0x0000_0000; // Header type 0 (device)
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
}
PciHeaderType::Bridge => {
registers[3] = 0x0001_0000; // Header type 1 (bridge)
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
}
};
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
// TODO(dverkamp): Status should be write-1-to-clear
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
let pi = if let Some(pi) = programming_interface {
pi.get_register_value()
} else {
0
};
registers[2] = u32::from(class_code.get_register_value()) << 24
| u32::from(subclass.get_register_value()) << 16
| u32::from(pi) << 8
| u32::from(revision_id);
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
match header_type {
PciHeaderType::Device => {
registers[3] = 0x0000_0000; // Header type 0 (device)
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
}
PciHeaderType::Bridge => {
registers[3] = 0x0001_0000; // Header type 1 (bridge)
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
}
};
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
let bars = [PciBar::default(); NUM_BAR_REGS];
(
registers,
writable_bits,
[PciBar::default(); NUM_BAR_REGS],
0,
0,
false,
None,
None,
)
};
PciConfiguration {
registers,
writable_bits,
bars,
rom_bar_addr: 0,
rom_bar_size: 0,
rom_bar_used: false,
last_capability: None,
msix_cap_reg_idx: None,
rom_bar_addr,
rom_bar_size,
rom_bar_used,
last_capability,
msix_cap_reg_idx,
msix_config,
}
}
@@ -610,18 +644,6 @@ impl PciConfiguration {
}
}
fn set_state(&mut self, state: &PciConfigurationState) {
self.registers.clone_from_slice(state.registers.as_slice());
self.writable_bits
.clone_from_slice(state.writable_bits.as_slice());
self.bars.clone_from_slice(state.bars.as_slice());
self.rom_bar_addr = state.rom_bar_addr;
self.rom_bar_size = state.rom_bar_size;
self.rom_bar_used = state.rom_bar_used;
self.last_capability = state.last_capability;
self.msix_cap_reg_idx = state.msix_cap_reg_idx;
}
/// Reads a 32bit register from `reg_idx` in the register map.
pub fn read_reg(&self, reg_idx: usize) -> u32 {
*(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
@@ -1046,16 +1068,11 @@ impl Pausable for PciConfiguration {}
impl Snapshottable for PciConfiguration {
fn id(&self) -> String {
String::from("pci_configuration")
String::from(PCI_CONFIGURATION_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id(), &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id())?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -1178,6 +1195,7 @@ mod tests {
0xABCD,
0x2468,
None,
None,
);
// Add two capabilities with different contents.
@@ -1234,6 +1252,7 @@ mod tests {
0xABCD,
0x2468,
None,
None,
);
let class_reg = cfg.read_reg(2);

View File

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

View File

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

View File

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

View File

@@ -3,16 +3,17 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
use crate::msi::{MsiConfigState, MSI_CONFIG_ID};
use crate::msix::MsixConfigState;
use crate::{
msi_num_enabled_vectors, BarReprogrammingParams, MsiCap, MsiConfig, MsixCap, MsixConfig,
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciBdf, PciCapabilityId,
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciExpressCapabilityId,
PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
PciHeaderType, PciSubclass, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE, PCI_CONFIGURATION_ID,
};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError;
use libc::{sysconf, _SC_PAGESIZE};
use std::any::Any;
use std::collections::{BTreeMap, HashMap};
use std::io;
@@ -37,6 +38,8 @@ use vm_migration::{
};
use vmm_sys_util::eventfd::EventFd;
pub(crate) const VFIO_COMMON_ID: &str = "vfio_common";
#[derive(Debug, Error)]
pub enum VfioPciError {
#[error("Failed to create user memory region: {0}")]
@@ -59,6 +62,14 @@ pub enum VfioPciError {
RegionAlignment,
#[error("Invalid region size")]
RegionSize,
#[error("Failed to retrieve MsiConfigState: {0}")]
RetrieveMsiConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve MsixConfigState: {0}")]
RetrieveMsixConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve PciConfigurationState: {0}")]
RetrievePciConfigurationState(#[source] anyhow::Error),
#[error("Failed to retrieve VfioCommonState: {0}")]
RetrieveVfioCommonState(#[source] anyhow::Error),
}
#[derive(Copy, Clone)]
@@ -407,6 +418,86 @@ pub(crate) struct VfioCommon {
}
impl VfioCommon {
pub(crate) fn new(
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
vfio_wrapper: Arc<dyn Vfio>,
subclass: &dyn PciSubclass,
bdf: PciBdf,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioPciError> {
let pci_configuration_state =
vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
.map_err(|e| {
VfioPciError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {}",
e
))
})?;
let configuration = PciConfiguration::new(
0,
0,
0,
PciClassCode::Other,
subclass,
None,
PciHeaderType::Device,
0,
0,
None,
pci_configuration_state,
);
let mut vfio_common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
interrupt: Interrupt {
intx: None,
msi: None,
msix: None,
},
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper,
patches: HashMap::new(),
};
let state: Option<VfioCommonState> = snapshot
.as_ref()
.map(|s| s.to_versioned_state())
.transpose()
.map_err(|e| {
VfioPciError::RetrieveVfioCommonState(anyhow!(
"Failed to get VfioCommonState from Snapshot: {}",
e
))
})?;
let msi_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSI_CONFIG_ID)
.map_err(|e| {
VfioPciError::RetrieveMsiConfigState(anyhow!(
"Failed to get MsiConfigState from Snapshot: {}",
e
))
})?;
let msix_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSIX_CONFIG_ID)
.map_err(|e| {
VfioPciError::RetrieveMsixConfigState(anyhow!(
"Failed to get MsixConfigState from Snapshot: {}",
e
))
})?;
if let Some(state) = state.as_ref() {
vfio_common.set_state(state, msi_state, msix_state)?;
} else {
vfio_common.parse_capabilities(bdf);
vfio_common.initialize_legacy_interrupt()?;
}
Ok(vfio_common)
}
pub(crate) fn allocate_bars(
&mut self,
allocator: &Arc<Mutex<SystemAllocator>>,
@@ -572,12 +663,7 @@ impl VfioCommon {
PciBarRegionType::Memory64BitRegion => {
// BAR allocation must be naturally aligned
mmio_allocator
.allocate(
restored_bar_addr,
region_size,
// SAFETY: FFI call. Trivially safe.
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
)
.allocate(restored_bar_addr, region_size, Some(region_size))
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
}
};
@@ -656,7 +742,13 @@ impl VfioCommon {
}
}
pub(crate) fn initialize_msix(&mut self, msix_cap: MsixCap, cap_offset: u32, bdf: PciBdf) {
pub(crate) fn initialize_msix(
&mut self,
msix_cap: MsixCap,
cap_offset: u32,
bdf: PciBdf,
state: Option<MsixConfigState>,
) {
let interrupt_source_group = self
.msi_interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -669,7 +761,9 @@ impl VfioCommon {
msix_cap.table_size(),
interrupt_source_group.clone(),
bdf.into(),
);
state,
)
.unwrap();
self.interrupt.msix = Some(VfioMsix {
bar: msix_config,
@@ -683,7 +777,12 @@ impl VfioCommon {
self.vfio_wrapper.read_config_word((cap + 2).into())
}
pub(crate) fn initialize_msi(&mut self, msg_ctl: u16, cap_offset: u32) {
pub(crate) fn initialize_msi(
&mut self,
msg_ctl: u16,
cap_offset: u32,
state: Option<MsiConfigState>,
) {
let interrupt_source_group = self
.msi_interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -692,7 +791,7 @@ impl VfioCommon {
})
.unwrap();
let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone());
let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone(), state).unwrap();
self.interrupt.msi = Some(VfioMsi {
cfg: msi_config,
@@ -719,7 +818,7 @@ impl VfioCommon {
// Parse capability only if the VFIO device
// supports MSI.
let msg_ctl = self.parse_msi_capabilities(cap_next);
self.initialize_msi(msg_ctl, cap_next as u32);
self.initialize_msi(msg_ctl, cap_next as u32, None);
}
}
}
@@ -730,7 +829,7 @@ impl VfioCommon {
// Parse capability only if the VFIO device
// supports MSI-X.
let msix_cap = self.parse_msix_capabilities(cap_next);
self.initialize_msix(msix_cap, cap_next as u32, bdf);
self.initialize_msix(msix_cap, cap_next as u32, bdf, None);
}
}
}
@@ -1097,7 +1196,12 @@ impl VfioCommon {
}
}
fn set_state(&mut self, state: &VfioCommonState) -> Result<(), VfioPciError> {
fn set_state(
&mut self,
state: &VfioCommonState,
msi_state: Option<MsiConfigState>,
msix_state: Option<MsixConfigState>,
) -> Result<(), VfioPciError> {
if let (Some(intx), Some(interrupt_source_group)) =
(&state.intx_state, self.legacy_interrupt_group.clone())
{
@@ -1112,11 +1216,11 @@ impl VfioCommon {
}
if let Some(msi) = &state.msi_state {
self.initialize_msi(msi.cap.msg_ctl, msi.cap_offset);
self.initialize_msi(msi.cap.msg_ctl, msi.cap_offset, msi_state);
}
if let Some(msix) = &state.msix_state {
self.initialize_msix(msix.cap, msix.cap_offset, msix.bdf.into());
self.initialize_msix(msix.cap, msix.cap_offset, msix.bdf.into(), msix_state);
}
Ok(())
@@ -1127,73 +1231,27 @@ impl Pausable for VfioCommon {}
impl Snapshottable for VfioCommon {
fn id(&self) -> String {
String::from("vfio_common")
String::from(VFIO_COMMON_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_common_snapshot =
Snapshot::new_from_versioned_state(&self.id(), &self.state())?;
let mut vfio_common_snapshot = Snapshot::new_from_versioned_state(&self.state())?;
// Snapshot PciConfiguration
vfio_common_snapshot.add_snapshot(self.configuration.snapshot()?);
vfio_common_snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
// Snapshot MSI
if let Some(msi) = &mut self.interrupt.msi {
vfio_common_snapshot.add_snapshot(msi.cfg.snapshot()?);
vfio_common_snapshot.add_snapshot(msi.cfg.id(), msi.cfg.snapshot()?);
}
// Snapshot MSI-X
if let Some(msix) = &mut self.interrupt.msix {
vfio_common_snapshot.add_snapshot(msix.bar.snapshot()?);
vfio_common_snapshot.add_snapshot(msix.bar.id(), msix.bar.snapshot()?);
}
Ok(vfio_common_snapshot)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(vfio_common_section) = snapshot
.snapshot_data
.get(&format!("{}-section", self.id()))
{
// It has to be invoked first as we want Interrupt to be initialized
// correctly before we try to restore MSI and MSI-X configurations.
self.set_state(&vfio_common_section.to_versioned_state()?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore VFIO_COMMON state {:?}", e))
})?;
// Restore PciConfiguration
if let Some(pci_config_snapshot) = snapshot.snapshots.get(&self.configuration.id()) {
self.configuration.restore(*pci_config_snapshot.clone())?;
}
// Restore MSI
if let Some(msi) = &mut self.interrupt.msi {
if let Some(msi_snapshot) = snapshot.snapshots.get(&msi.cfg.id()) {
msi.cfg.restore(*msi_snapshot.clone())?;
}
if msi.cfg.enabled() {
self.enable_msi().unwrap();
}
}
// Restore MSI-X
if let Some(msix) = &mut self.interrupt.msix {
if let Some(msix_snapshot) = snapshot.snapshots.get(&msix.bar.id()) {
msix.bar.restore(*msix_snapshot.clone())?;
}
if msix.bar.enabled() {
self.enable_msix().unwrap();
}
}
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find VFIO_COMMON snapshot section"
)))
}
}
/// VfioPciDevice represents a VFIO PCI device.
@@ -1224,48 +1282,22 @@ impl VfioPciDevice {
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
iommu_attached: bool,
bdf: PciBdf,
restoring: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioPciError> {
let device = Arc::new(device);
device.reset();
let configuration = PciConfiguration::new(
0,
0,
0,
PciClassCode::Other,
&PciVfioSubclass::VfioSubclass,
None,
PciHeaderType::Device,
0,
0,
None,
);
let vfio_wrapper = VfioDeviceWrapper::new(Arc::clone(&device));
let mut common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
interrupt: Interrupt {
intx: None,
msi: None,
msix: None,
},
let common = VfioCommon::new(
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
patches: HashMap::new(),
};
// No need to parse capabilities from the device if on the restore path.
// The initialization will be performed later when restore() will be
// called.
if !restoring {
common.parse_capabilities(bdf);
common.initialize_legacy_interrupt()?;
}
Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
&PciVfioSubclass::VfioSubclass,
bdf,
vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
)?;
let vfio_pci_device = VfioPciDevice {
id,
@@ -1284,10 +1316,8 @@ impl VfioPciDevice {
self.iommu_attached
}
fn align_page_size(address: u64) -> u64 {
// SAFETY: FFI call. Trivially safe.
let page_size = unsafe { sysconf(_SC_PAGESIZE) as u64 };
(address + page_size - 1) & !(page_size - 1)
fn align_4k(address: u64) -> u64 {
(address + 0xfff) & 0xffff_ffff_ffff_f000
}
fn is_4k_aligned(address: u64) -> bool {
@@ -1347,7 +1377,6 @@ impl VfioPciDevice {
let mut sparse_areas = Vec::new();
let mut current_offset = 0;
for (range_offset, range_size) in inter_ranges {
let range_offset = Self::align_page_size(range_offset);
if range_offset > current_offset {
sparse_areas.push(VfioRegionSparseMmapArea {
offset: current_offset,
@@ -1355,13 +1384,13 @@ impl VfioPciDevice {
});
}
current_offset = Self::align_page_size(range_offset + range_size);
current_offset = Self::align_4k(range_offset + range_size);
}
if region_size > current_offset {
sparse_areas.push(VfioRegionSparseMmapArea {
offset: Self::align_page_size(current_offset),
size: Self::align_page_size(region_size - current_offset),
offset: current_offset,
size: region_size - current_offset,
});
}
@@ -1431,6 +1460,7 @@ impl VfioPciDevice {
)?;
for area in sparse_areas.iter() {
// SAFETY: FFI call with correct arguments
let host_addr = unsafe {
libc::mmap(
null_mut(),
@@ -1497,6 +1527,7 @@ impl VfioPciDevice {
error!("Could not remove the userspace memory region: {}", e);
}
// SAFETY: FFI call with correct arguments
let ret = unsafe {
libc::munmap(
user_memory_region.host_addr as *mut libc::c_void,
@@ -1708,28 +1739,13 @@ impl Snapshottable for VfioPciDevice {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_pci_dev_snapshot = Snapshot::new(&self.id);
let mut vfio_pci_dev_snapshot = Snapshot::default();
// Snapshot VfioCommon
vfio_pci_dev_snapshot.add_snapshot(self.common.snapshot()?);
vfio_pci_dev_snapshot.add_snapshot(self.common.id(), self.common.snapshot()?);
Ok(vfio_pci_dev_snapshot)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
// Restore VfioCommon
if let Some(vfio_common_snapshot) = snapshot.snapshots.get(&self.common.id()) {
self.common.restore(*vfio_common_snapshot.clone())?;
self.map_mmio_regions().map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not map MMIO regions for VfioPciDevice on restore {:?}",
e
))
})?;
}
Ok(())
}
}
impl Transportable for VfioPciDevice {}
impl Migratable for VfioPciDevice {}

View File

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

View File

@@ -3,16 +3,13 @@ name = "performance-metrics"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
build = "build.rs"
build = "../build.rs"
[dependencies]
clap = { version = "4.0.29", features = ["wrap_help","cargo"] }
argh = "0.1.9"
dirs = "4.0.0"
serde = { version = "1.0.150", features = ["rc", "derive"] }
serde_json = "1.0.89"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
test_infra = { path = "../test_infra" }
thiserror = "1.0.37"
thiserror = "1.0.38"
wait-timeout = "0.2.0"
[build-dependencies]
clap = { version = "4.0.29", features = ["cargo"] }

View File

@@ -1,26 +0,0 @@
// Copyright © 2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use(crate_version)]
extern crate clap;
use std::process::Command;
fn main() {
let mut git_human_readable = "v".to_owned() + crate_version!();
if let Ok(git_out) = Command::new("git").args(["describe", "--dirty"]).output() {
if git_out.status.success() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
git_human_readable = git_out_str;
}
}
}
// This println!() has a special behavior, as it will set the environment
// variable GIT_HUMAN_READABLE, so that it can be reused from the binary.
// Particularly, this is used from the main.rs to display the exact
// version information.
println!("cargo:rustc-env=GIT_HUMAN_READABLE={git_human_readable}");
}

View File

@@ -5,16 +5,14 @@
// Custom harness to run performance tests
extern crate test_infra;
#[macro_use(crate_authors)]
extern crate clap;
mod performance_tests;
use clap::{Arg, ArgAction, Command as ClapCommand};
use argh::FromArgs;
use performance_tests::*;
use serde::{Deserialize, Serialize};
use std::{
env, fmt,
fmt,
process::Command,
sync::{mpsc::channel, Arc},
thread,
@@ -129,8 +127,8 @@ pub struct PerformanceTestControl {
test_iterations: u32,
num_queues: Option<u32>,
queue_size: Option<u32>,
net_rx: Option<bool>,
fio_ops: Option<FioOps>,
net_control: Option<(bool, bool)>, // First bool is for RX(true)/TX(false), second bool is for bandwidth or PPS
fio_control: Option<(FioOps, bool)>, // Second parameter controls whether we want bandwidth or IOPS
num_boot_vcpus: Option<u8>,
}
@@ -146,11 +144,13 @@ impl fmt::Display for PerformanceTestControl {
if let Some(o) = self.queue_size {
output = format!("{output}, queue_size = {o}");
}
if let Some(o) = self.net_rx {
output = format!("{output}, net_rx = {o}");
if let Some(o) = self.net_control {
let (rx, bw) = o;
output = format!("{output}, rx = {rx}, bandwidth = {bw}");
}
if let Some(o) = &self.fio_ops {
output = format!("{output}, fio_ops = {o}");
if let Some(o) = &self.fio_control {
let (ops, bw) = o;
output = format!("{output}, fio_ops = {ops}, bandwidth = {bw}");
}
write!(f, "{output}")
@@ -164,8 +164,8 @@ impl PerformanceTestControl {
test_iterations: 5,
num_queues: None,
queue_size: None,
net_rx: None,
fio_ops: None,
net_control: None,
fio_control: None,
num_boot_vcpus: Some(1),
}
}
@@ -262,7 +262,7 @@ mod adjuster {
}
}
const TEST_LIST: [PerformanceTest; 17] = [
const TEST_LIST: [PerformanceTest; 29] = [
PerformanceTest {
name: "boot_time_ms",
func_ptr: performance_boot_time,
@@ -321,7 +321,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_rx: Some(true),
net_control: Some((true, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -332,7 +332,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_rx: Some(false),
net_control: Some((false, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -343,7 +343,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_rx: Some(true),
net_control: Some((true, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -354,18 +354,62 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_rx: Some(false),
net_control: Some((false, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_rx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_control: Some((true, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_tx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_control: Some((false, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_rx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_control: Some((true, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_tx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_control: Some((false, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_read_MiBps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::Read),
fio_control: Some((FioOps::Read, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -376,7 +420,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::Write),
fio_control: Some((FioOps::Write, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -387,7 +431,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomRead),
fio_control: Some((FioOps::RandomRead, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -398,7 +442,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomWrite),
fio_control: Some((FioOps::RandomWrite, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -409,7 +453,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::Read),
fio_control: Some((FioOps::Read, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -420,7 +464,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::Write),
fio_control: Some((FioOps::Write, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -431,7 +475,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomRead),
fio_control: Some((FioOps::RandomRead, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -442,11 +486,99 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomWrite),
fio_control: Some((FioOps::RandomWrite, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::Read, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::Write, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_random_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::RandomRead, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_random_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::RandomWrite, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::Read, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::Write, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_random_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::RandomRead, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_random_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::RandomWrite, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
];
fn run_test_with_timeout(
@@ -494,39 +626,37 @@ fn date() -> String {
String::from_utf8_lossy(&output.stdout).trim().to_string()
}
#[derive(FromArgs)]
/// Generate the performance metrics data for Cloud Hypervisor
struct Options {
#[argh(switch, long = "list-tests")]
/// print the list of available metrics tests
list_tests: bool,
#[argh(option, long = "test-filter")]
/// filter metrics tests to run based on provided keywords
keywords: Vec<String>,
#[argh(option, long = "report-file")]
/// report file. Stderr is used if not specified
report_file: Option<String>,
#[argh(option, long = "iterations")]
/// override number of test iterations
iterations: Option<u32>,
#[argh(switch, short = 'V', long = "version")]
/// print version information
version: bool,
}
fn main() {
let cmd_arguments = ClapCommand::new("performance-metrics")
.version(env!("GIT_HUMAN_READABLE"))
.author(crate_authors!())
.about("Generate the performance metrics data for Cloud Hypervisor")
.arg(
Arg::new("test-filter")
.long("test-filter")
.help("Filter metrics tests to run based on provided keywords")
.num_args(1)
.required(false),
)
.arg(
Arg::new("list-tests")
.long("list-tests")
.help("Print the list of availale metrics tests")
.num_args(0)
.action(ArgAction::SetTrue)
.required(false),
)
.arg(
Arg::new("report-file")
.long("report-file")
.help("Report file. Standard error is used if not specified")
.num_args(1),
)
.arg(
Arg::new("iterations")
.long("iterations")
.help("Override number of test iterations")
.num_args(1),
)
.get_matches();
let opts: Options = argh::from_env();
if opts.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}
// It seems that the tool (ethr) used for testing the virtio-net latency
// is not stable on AArch64, and therefore the latency test is currently
@@ -536,7 +666,7 @@ fn main() {
.filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us"))
.collect();
if cmd_arguments.get_flag("list-tests") {
if opts.list_tests {
for test in test_list.iter() {
println!("\"{}\" ({})", test.name, test.control);
}
@@ -544,10 +674,7 @@ fn main() {
return;
}
let test_filter = match cmd_arguments.get_many::<String>("test-filter") {
Some(s) => s.collect(),
None => Vec::new(),
};
let test_filter = opts.keywords.iter().collect::<Vec<&String>>();
// Run performance tests sequentially and report results (in both readable/json format)
let mut metrics_report: MetricsReport = Default::default();
@@ -555,11 +682,7 @@ fn main() {
init_tests();
let overrides = Arc::new(PerformanceTestOverrides {
test_iterations: cmd_arguments
.get_one::<String>("iterations")
.map(|s| s.parse())
.transpose()
.unwrap_or_default(),
test_iterations: opts.iterations,
});
for test in test_list.iter() {
@@ -578,19 +701,18 @@ fn main() {
cleanup_tests();
let mut report_file: Box<dyn std::io::Write + Send> =
if let Some(file) = cmd_arguments.get_one::<String>("report-file") {
Box::new(
std::fs::File::create(std::path::Path::new(file))
.map_err(|e| {
eprintln!("Error opening report file: {file}: {e}");
std::process::exit(1);
})
.unwrap(),
)
} else {
Box::new(std::io::stdout())
};
let mut report_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = opts.report_file {
Box::new(
std::fs::File::create(std::path::Path::new(file))
.map_err(|e| {
eprintln!("Error opening report file: {file}: {e}");
std::process::exit(1);
})
.unwrap(),
)
} else {
Box::new(std::io::stdout())
};
report_file
.write_all(

View File

@@ -78,7 +78,7 @@ fn direct_kernel_boot_path() -> PathBuf {
pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
let test_timeout = control.test_timeout;
let rx = control.net_rx.unwrap();
let (rx, bandwidth) = control.net_control.unwrap();
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = performance_test_new_guest(Box::new(focal));
@@ -105,7 +105,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx).unwrap()
measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx, bandwidth).unwrap()
});
let _ = child.kill();
@@ -334,7 +334,7 @@ pub fn performance_boot_time_pmem(control: &PerformanceTestControl) -> f64 {
pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
let test_timeout = control.test_timeout;
let num_queues = control.num_queues.unwrap();
let fio_ops = control.fio_ops.as_ref().unwrap();
let (fio_ops, bandwidth) = control.fio_control.as_ref().unwrap();
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = performance_test_new_guest(Box::new(focal));
@@ -358,11 +358,13 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
)
.as_str(),
"--disk",
format!(
"path={}",
guest.disk_config.disk(DiskType::CloudInit).unwrap()
)
.as_str(),
"--disk",
format!("path={BLK_IO_TEST_IMG}").as_str(),
])
.default_net()
@@ -387,7 +389,11 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
.unwrap();
// Parse fio output
parse_fio_output(&output, fio_ops, num_queues).unwrap()
if *bandwidth {
parse_fio_output(&output, fio_ops, num_queues).unwrap()
} else {
parse_fio_output_iops(&output, fio_ops, num_queues).unwrap()
}
});
let _ = child.kill();
@@ -424,7 +430,7 @@ mod tests {
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), true).unwrap(),
parse_iperf3_output(output.as_bytes(), true, true).unwrap(),
23957198874.604115
);
@@ -443,9 +449,31 @@ mod tests {
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), false).unwrap(),
parse_iperf3_output(output.as_bytes(), false, true).unwrap(),
39520744482.79
);
let output = r#"
{
"end": {
"sum": {
"start": 0,
"end": 5.000036,
"seconds": 5.000036,
"bytes": 29944971264,
"bits_per_second": 47911877363.396217,
"jitter_ms": 0.0038609822983198556,
"lost_packets": 16,
"packets": 913848,
"lost_percent": 0.0017508382137948542,
"sender": true
}
}
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), true, false).unwrap(),
182765.08409139456
);
}
#[test]

View File

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

View File

@@ -66,7 +66,7 @@ impl QcowRawFile {
non_zero_flags: u64,
) -> io::Result<()> {
self.file.seek(SeekFrom::Start(offset))?;
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &mut self.file);
for addr in table {
let val = if *addr == 0 {
0
@@ -91,7 +91,7 @@ impl QcowRawFile {
/// Writes a refcount block to the file.
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
self.file.seek(SeekFrom::Start(offset))?;
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &mut self.file);
for count in table {
buffer.write_u16::<BigEndian>(*count)?;
}

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