Compare commits

...

150 Commits
v18.0 ... v19.0

Author SHA1 Message Date
Rob Bradford
d00eb4aa25 build: Release v19.0
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-10-14 16:10:17 +01:00
Bo Chen
a1d8b63d86 Dockerfile: Build and install SPDK NVMe to the docker image
Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-10-13 14:20:19 +01:00
dependabot[bot]
0ce47c0538 build: bump proc-macro2 from 1.0.29 to 1.0.30 in /fuzz
Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 1.0.29 to 1.0.30.
- [Release notes](https://github.com/alexcrichton/proc-macro2/releases)
- [Commits](https://github.com/alexcrichton/proc-macro2/compare/1.0.29...1.0.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-13 10:20:56 +02:00
dependabot[bot]
828156db38 build: bump proc-macro2 from 1.0.29 to 1.0.30
Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 1.0.29 to 1.0.30.
- [Release notes](https://github.com/alexcrichton/proc-macro2/releases)
- [Commits](https://github.com/alexcrichton/proc-macro2/compare/1.0.29...1.0.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-13 09:30:17 +02:00
Rob Bradford
52df97e659 build: Add GH action to check for DCO (Signed-Off-By)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-10-12 16:44:26 +01:00
dependabot[bot]
8e65d812cb build: bump vm-fdt from 57796cd to 9c2b252
Bumps [vm-fdt](https://github.com/rust-vmm/vm-fdt) from `57796cd` to `9c2b252`.
- [Release notes](https://github.com/rust-vmm/vm-fdt/releases)
- [Commits](57796cde6a...9c2b252dc1)

---
updated-dependencies:
- dependency-name: vm-fdt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 13:47:32 +00:00
dependabot[bot]
610d694f1d build: bump thiserror from 1.0.29 to 1.0.30
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.29 to 1.0.30.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.29...1.0.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 09:45:31 +02:00
dependabot[bot]
25c6733feb build: bump ssh2 from 0.9.1 to 0.9.3
Bumps [ssh2](https://github.com/alexcrichton/ssh2-rs) from 0.9.1 to 0.9.3.
- [Release notes](https://github.com/alexcrichton/ssh2-rs/releases)
- [Commits](https://github.com/alexcrichton/ssh2-rs/compare/0.9.1...0.9.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 09:44:57 +02:00
dependabot[bot]
39af0df279 build: bump thiserror from 1.0.29 to 1.0.30 in /fuzz
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.29 to 1.0.30.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.29...1.0.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 05:09:18 +00:00
dependabot[bot]
5cc2876516 build: bump mshv-ioctls from 74e46d4 to 99da566
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `74e46d4` to `99da566`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](74e46d4eac...99da566389)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 05:09:12 +00:00
dependabot[bot]
9009e785d9 build: bump synstructure from 0.12.5 to 0.12.6
Bumps [synstructure](https://github.com/mystor/synstructure) from 0.12.5 to 0.12.6.
- [Release notes](https://github.com/mystor/synstructure/releases)
- [Commits](https://github.com/mystor/synstructure/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 05:09:03 +00:00
dependabot[bot]
a3231b1727 build: bump libssh2-sys from 0.2.21 to 0.2.23
Bumps [libssh2-sys](https://github.com/alexcrichton/ssh2-rs) from 0.2.21 to 0.2.23.
- [Release notes](https://github.com/alexcrichton/ssh2-rs/releases)
- [Commits](https://github.com/alexcrichton/ssh2-rs/compare/libssh2-sys-0.2.21...libssh2-sys-0.2.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 05:08:54 +00:00
Sebastien Boeuf
76a036e96d hypervisor: kvm: Add missing MSR related to Hyper-V
When the synthetic interrupt controller is enabled, an extra set of MSRs
must be stored in case of migration. There was one MSR missing in the
list, HV_X64_MSR_SINT14 corresponding to the 15th interrupt source from
the synthetic interrupt controller.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-11 15:30:13 +02:00
Wei Liu
3e0bf235bb tests: consolidate arch constants into modules
This avoids having cfg(...) for each individual line. No functional
change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2021-10-08 10:51:14 -07:00
dependabot[bot]
d0bafc72f8 build: bump iced-x86 from 1.14.0 to 1.15.0 in /fuzz
Bumps [iced-x86](https://github.com/icedland/iced) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/icedland/iced/releases)
- [Commits](https://github.com/icedland/iced/compare/v1.14.0...v1.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-08 08:05:03 +00:00
dependabot[bot]
2f3502eacc build: bump iced-x86 from 1.14.0 to 1.15.0
Bumps [iced-x86](https://github.com/icedland/iced) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/icedland/iced/releases)
- [Commits](https://github.com/icedland/iced/compare/v1.14.0...v1.15.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>
2021-10-08 07:33:42 +00:00
Sebastien Boeuf
30cafccd23 deps: Move to vhost 0.2.0
There's no need to patch the vhost crate anymore since the fixes we were
looking for have been released as part of 0.2.0 on crates.io.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-07 13:33:35 +01:00
dependabot[bot]
88ebf565e0 build: bump cc from 1.0.70 to 1.0.71 in /fuzz
Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.70 to 1.0.71.
- [Release notes](https://github.com/alexcrichton/cc-rs/releases)
- [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.70...1.0.71)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-07 01:36:27 +00:00
dependabot[bot]
0344805ed0 build: bump syn from 1.0.78 to 1.0.80 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.78 to 1.0.80.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.78...1.0.80)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-07 01:36:23 +00:00
dependabot[bot]
22873ae79e build: bump cc from 1.0.70 to 1.0.71
Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.70 to 1.0.71.
- [Release notes](https://github.com/alexcrichton/cc-rs/releases)
- [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.70...1.0.71)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-07 01:36:18 +00:00
dependabot[bot]
7dacfa3edc build: bump syn from 1.0.78 to 1.0.80
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.78 to 1.0.80.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.78...1.0.80)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-07 01:36:14 +00:00
Sebastien Boeuf
58d8206e2b migration: Use MemoryManager restore code path
Instead of creating a MemoryManager from scratch, let's reuse the same
code path used by snapshot/restore, so that memory regions are created
identically to what they were on the source VM.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
1e1e61614c vmm: memory_manager: Leverage new codepath for snapshot/restore
Now that all the pieces are in place, we can restore a VM with the new
codepath that restores properly all memory regions, allowing for ACPI
memory hotplug to work properly with snapshot/restore feature.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
6a55768d94 vmm: Create MemoryManager from restore data
Extending the MemoryManager::new() function to be able to create a
MemoryManager from data that have been previously stored instead of
always creating everything from scratch.

This change brings real added value as it allows a VM to be restored
respecting the proper memory layout instead of hoping the regions will
be created the way they were before.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
5b177b205b arch, vmm: Extend the data being snapshot
Storing multiple data coming from the MemoryManager in order to be able
to restore without creating everything from scratch.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
f440976a7c vmm: memory_manager: Add a way to restore memory regions properly
This new function will be able to restore memory regions and memory
zones based on the GuestMemoryMapping list that will be provided through
snapshot/restore and migration phases.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
0d573ae86c vmm: memory_manager: Add file_offset to GuestRamMapping
This will help restoring the region with the correct file offset for the
memory mapping.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
01420f5195 vmm: memory_manager: Add virtio_mem to GuestRamMapping
This will help identify if the range belongs to a virtio-mem region or
not.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
dfb1829f65 vmm: memory_manager: Add zone_id to GuestRamMapping
This can help identifying which zone relates to which memory range.
This is going to be useful when recreating GuestMemory regions from
the previous layout instead of having to recreate everything from
scratch.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
b5d11f72b3 vmm: memory_manager: Factorize allocation of ranges
Create a dedicated function to factorize the allocation of the memory
ranges, and helping with the simplification of MemoryManager::new()
function.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
00951f17d4 vmm: memory_manager: Simplify regions creation
By updating the list of GuestMemory regions with the virtio-mem ones
before the creation of the MemoryManager, we know the GuestMemory is up
to date and the allocation of memory ranges is simplified afterwards.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
Sebastien Boeuf
63c6c78c4e vmm: memory_manager: Factorize configuration validation
In order to simplify MemoryManager::new() function. let's move the
memory configuration validation to its own function.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-10-06 18:35:49 -07:00
dependabot[bot]
3fbdd7e16c build: bump quote from 1.0.9 to 1.0.10
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.9...1.0.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-06 03:35:50 +00:00
dependabot[bot]
455b0d5b62 build: bump quote from 1.0.9 to 1.0.10 in /fuzz
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.9...1.0.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-06 03:35:45 +00:00
Muminul Islam
bbefbe9273 tools: Add a script to check image compatibility
This script checks if an image is compatible with Cloud Hypervisor.
At first, it detects the image type(raw or qcow2),
partition type whether it is DOS or GPT.
Then it mounts the image and checks if VIRTIO Configs
are enabled in the kernel config. In the end, it provides
a message about the compatibility of the image.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2021-10-05 14:40:10 +01:00
Rob Bradford
84fc0e093d vmm: Move PciSegment to new file
Move the PciSegment struct and the associated code to a new file. This
will allow some clearer separation between the core DeviceManager and
PCI handling.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-10-05 10:54:07 +01:00
Rob Bradford
0eb78ab177 vmm: Extract PCI related state from DeviceManager
Move the PCI related state from the DeviceManager struct to a PciSegment
struct inside the DeviceManager. This is in preparation for multiple
segment support. Currently this state is just the bus itself, the MMIO
and PIO config devices and hotplug related state.

The main change that this required is using the Arc<Mutex<PciBus>> in
the device addition logic in order to ensure that
the bus could be created earlier.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-10-05 10:54:07 +01:00
dependabot[bot]
9aadbbe6d9 build: bump syn from 1.0.77 to 1.0.78 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.77 to 1.0.78.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.77...1.0.78)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 23:50:11 +00:00
dependabot[bot]
dc822be5e2 build: bump syn from 1.0.77 to 1.0.78
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.77 to 1.0.78.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.77...1.0.78)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 23:50:00 +00:00
Bo Chen
1a4747a20f Build: Seccompiler: Move to use the released version from crate.io
Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-10-01 11:34:54 -07:00
Rob Bradford
83066cf58e vmm: Set a default maximum physical address size
When using PVH for booting (which we use for all firmwares and direct
kernel boot) the Linux kernel does not configure LA57 correctly. As such
we need to limit the address space to the maximum 4-level paging address
space.

If the user knows that their guest image can take advantage of the
5-level addressing and they need it for their workload then they can
increase the physical address space appropriately.

This PR removes the TDX specific handling as the new address space limit
is below the one that that code specified.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-10-01 08:59:15 -07:00
Sebastien Boeuf
495e444ca6 vmm: Add ACPI tables to TdVmmData when running TDX
Whenever running TDX, we must pass the ACPI tables to the TDVF firmware
running in the guest. The proper way to do this is by adding the tables
to the TdHob as a TdVmmData type, so that TDVF will know how to access
these tables and expose them to the guest OS.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-30 06:35:55 -07:00
Sebastien Boeuf
b99a3a7dc9 vmm: Factorize ACPI tables creation inside boot() function
Instead of having the ACPI tables being created both in x86_64 and
aarch64 implementations of configure_system(), we can remove the
duplicated code by moving the ACPI tables creation in vm.rs inside the
boot() function.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-30 06:35:55 -07:00
Sebastien Boeuf
84a741a3fa arch: x86_64: tdx: Add TD_VMM_DATA support
Adding the definitions and helpers to build TD_VMM_DATA regions as part
of the TD_HOB.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-30 06:35:55 -07:00
Henry Wang
db5d66747e tests: Enable device hotplug test cases on AArch64
On AArch64, device hotplug can be enabled with ACPI. Therefore,
this commit enables the hotplug test case for following devices:

- PCI bar reprogramming
- virtio-disk
- virtio-net
- macvtap
- virtio-vsock
- virtio-pmem: Works with the latest reference kernel
- virtio-fs: Works with the latest reference kernel

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2021-09-29 17:37:43 +01:00
Henry Wang
dd6f07da23 docs: Add notes for PCI device hotplug on AArch64
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2021-09-29 17:37:43 +01:00
Henry Wang
8c135030d0 tests: Mute warning when building tests on AArch64
Currently vfio and nested virtualization is not used on AArch64,
and SGX is a x86_64 only feature. Therefore this commit adds the
architecture gates for helper functions related to vfio, SGX, and
nested virtualization to mute warnings when building tests on the
AArch64 platform.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2021-09-29 17:37:43 +01:00
Li Yu
0468598fa3 docs: update prefault in memory
Update introduction of option `prefault`.

In addition, this commit also did the following:
- Rearrange options, synchronize order with `config.rs`.
- Break long lines in `hugepages`.
- Update old example of `hugepages` in memory zone.

Signed-off-by: Li Yu <liyu.yukiteru@bytedance.com>
2021-09-29 09:01:22 -07:00
Rob Bradford
7b7a3abfaa build: Use "common" feature in default features
This has the side effect of turning "fwdebug" on but that is
advantageous.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-29 16:33:05 +01:00
Jianyong Wu
277ff84e55 tests: Enable memory hotplug and virtio_balloon on arm64
Memory hotplug and virtio_balloon works on arm64 with:

- memory hotplug: An updated kernel using ACPI
- virtio balloon: `stress` installed in the cloud image

Therefore, we can enable test cases for them in integration test.

Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2021-09-29 16:32:51 +01:00
Jianyong Wu
a9f50dda08 resources: Enable rtc_drv_efi in arm64 kernel config
rtc-efi is used when system boot from UEFI thus the related kernel
driver should be enabled.

Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
2021-09-29 16:32:51 +01:00
Muminul Islam
73244aa6f2 tests: Disable unsupported tests for MSHV
On MSHV some of the integration test cases are not supported yet
or still in progress. This patch disables all those test cases.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2021-09-29 15:02:50 +01:00
Muminul Islam
6454c677d0 scripts: populate build and test features based on hypervisor
Signed-off-by: Muminul Islam <muislam@microsoft.com>
2021-09-29 15:02:50 +01:00
Muminul Islam
ca4857b5e6 scripts: check hypervisor before running the test
Add two more checks if the hypervisor value is correct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2021-09-29 15:02:50 +01:00
Rob Bradford
1511cbda87 tests, scripts: Update custom aarch64 image to include "stress"
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-29 15:01:46 +01:00
Yu Li
08021087ec vmm: add prefault option in memory and memory-zone
The argument `prefault` is provided in MemoryManager, but it can
only be used by SGX and restore.
With prefault (MAP_POPULATE) been set, subsequent page faults will
decrease during running, although it will make boot slower.

This commit adds `prefault` in MemoryConfig and MemoryZoneConfig.
To resolve conflict between memory and restore, argument
`prefault` has been changed from `bool` to `Option<bool>`, when
its value is None, config from memory will be used, otherwise
argument in Option will be used.

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2021-09-29 14:17:35 +02:00
dependabot[bot]
90d79fa76b build: bump smallvec from 1.6.1 to 1.7.0
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.6.1 to 1.7.0.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.6.1...v1.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-29 05:50:40 +00:00
Sebastien Boeuf
bebc5f957e scripts: Pin virtiofsd-rs to a specific revision
In order to avoid CI issues, from now on, we'll update the virtiofsd-rs
revision manually.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 19:48:17 +01:00
Sebastien Boeuf
5ac013df8b virtio-devices: vhost-user: Set reply_ack conditionally
Setting the reply_ack should depend on the set of acknowledged features
containing the REPLY_ACK flag.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 19:48:17 +01:00
Sebastien Boeuf
562a57012f tests: Update virtiofsd-rs to use the cache option
Now that virtiofsd-rs binary supports the cache option, let's use it.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 19:48:17 +01:00
Sebastien Boeuf
93d19329f9 tests: Extend snapshot/restore test with virtio-mem
Add virtio-mem plug/unplug testing to the existing snapshot/restore
integration test.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
612dc544a8 tests: Extend live migration testing with virtio-mem
Adding some bits to the existing live migration test with NUMA in order
to properly validate virtio-mem works with live migration.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
59031531b6 vmm: Simplify the way memory is snapshot and restored
By using a single file for storing the memory ranges, we simplify the
way snapshot/restore works by avoiding multiples files, but the main and
more important point is that we have now a way to save only the ranges
that matter. In particular, the ranges related to virtio-mem regions are
not always fully hotplugged, meaning we don't want to save the entire
region. That's where the usage of memory ranges is interesting as it
lets us optimize the snapshot/restore process when one or multiple
virtio-mem regions are involved.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
2569621c4b vm-migration: Derive Versionize for MemoryRangeTable structure
During snapshot/restore we will need to store this structure, which is
why it must derive the Versionize trait.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
1ea63f50a1 vmm: Move MemoryRangeTable creation to the MemoryManager
The function memory_range_table() will be reused by the MemoryManager in
a following patch to describe all the ranges that we should snapshot.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
86f86c5348 vmm: Optimize migration for virtio-mem
Copy only the memory ranges that have been plugged through virtio-mem,
allowing for an interesting optimization regarding the time it takes to
migrate a large virtio-mem device. Even if the hotpluggable space is
very large (say 64GiB), if only 1GiB has been previously added to the
VM, only 1GiB will be sent to the destination VM, avoiding the transfer
of the remaining 63GiB which are unused.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
0fb24ea3ae virtio-devices: mem: Discard unplugged ranges only on activate()
In order to support correctly the snapshot/restore and migration use
cases, we must be careful with the ranges that we discard by punching
holes. On restore, there might be some ranges already plugged in,
meaning they should not be discarded. That's why we loop over the list
of blocks to discard only the ranges that are marked as unplugged.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
e390775bcb vmm, virtio-devices: Move BlocksState creation to the MemoryManager
By creating the BlocksState object in the MemoryManager, we can directly
provide it to the virtio-mem device when being created. This will allow
the MemoryManager through each VirtioMemZone to have a handle onto the
blocks that are plugged at any point in time.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
4450c44fbc virtio-devices: mem: Create a MemoryRangeTable from BlocksState
This is going to be useful to let virtio-mem report the list of ranges
that are currently plugged, so that both snapshot/restore and migration
will copy only what is needed.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
a1caa6549a vmm: Add page size as a parameter for MemoryRangeTable::from_bitmap()
This will be helpful to support the creation of a MemoryRangeTable from
virtio-mem, as it uses 2M pages.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
af3a59aa33 virtio-devices: mem: Add constructor for BlocksState
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
d7115ec656 virtio-devices: mem: Add snapshot/restore support
Adding the snapshot/restore support along with migration as well,
allowing a VM with virtio-mem devices attached to be properly
migrated.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
7bbcc0f849 vmm: memory_manager: Make sure the hotplugged_size is up to date
The amount of memory plugged in the virtio-mem region should always be
kept up to date in the hotplugged_size field from VirtioMemZone.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
c4dc7a583d vmm: memory_manager: Simplify the MemoryManager structure
There's no need to duplicate the GuestMemory for snapshot purpose, as we
always have a handle onto the GuestMemory through the guest_memory
field.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Sebastien Boeuf
74485924b1 vmm: memory_manager: Simplification to avoid unnecessary locking
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-28 10:15:22 -07:00
Rob Bradford
4889999277 vmm: Only advertise a single PCI bus
Since we only support a single PCI bus right now advertise only a single
bus in the ACPI tables. This reduces the number of VM exits from probing
substantially.

Number of PCI config I/O port exits: 17871 -> 1551 (91% reduction) with
direct kernel boot.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-28 14:10:10 +02:00
dependabot[bot]
eda0dc20d3 build: bump libc from 0.2.102 to 0.2.103
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.102 to 0.2.103.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.102...0.2.103)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-28 10:45:35 +00:00
dependabot[bot]
1e9c84af0f build: bump vm-fdt from ddb3fad to 57796cd
Bumps [vm-fdt](https://github.com/rust-vmm/vm-fdt) from `ddb3fad` to `57796cd`.
- [Release notes](https://github.com/rust-vmm/vm-fdt/releases)
- [Commits](ddb3fad524...57796cde6a)

---
updated-dependencies:
- dependency-name: vm-fdt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-28 10:37:00 +00:00
Rob Bradford
b50519651c vmm: Simplify slot eject code in PCI ACPI device code
Use a simpler method for extracting the affected slot on the eject
command. Also update the terminology to reflect that this a slot rather
than a bdf (which is what device id refers to elsewhere.)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-28 12:03:23 +02:00
dependabot[bot]
08d859a7dd build: bump mshv-ioctls from 0b58354 to 74e46d4
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `0b58354` to `74e46d4`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](0b5835475c...74e46d4eac)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-28 09:25:09 +00:00
dependabot[bot]
0dad7d9331 build: bump pkg-config from 0.3.19 to 0.3.20
Bumps [pkg-config](https://github.com/rust-lang/pkg-config-rs) from 0.3.19 to 0.3.20.
- [Release notes](https://github.com/rust-lang/pkg-config-rs/releases)
- [Changelog](https://github.com/rust-lang/pkg-config-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/pkg-config-rs/compare/0.3.19...0.3.20)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-28 09:03:04 +00:00
dependabot[bot]
a496cecef1 build: bump libc from 0.2.102 to 0.2.103 in /fuzz
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.102 to 0.2.103.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.102...0.2.103)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-28 09:01:16 +00:00
William Douglas
a8f063db7c vmm: Refactor serial buffer to allow flush on PTY when writable
Refactor the serial buffer handling in order to write the serial
buffer's output to a PTY connected after the serial device stops being
written to by the guest.

This change moves the serial buffer initialization inside the serial
manager. That is done to allow the serial buffer to be made aware of
the PTY and epoll fds needed in order to modify the
EpollDispatch::File trigger. These are then used by the serial buffer
to trigger an epoll event when the PTY fd is writable and the buffer
has content in it. They are also used to remove the trigger when the
buffer is emptied in order to avoid unnecessary wake-ups.

Signed-off-by: William Douglas <william.douglas@intel.com>
2021-09-27 14:18:21 +01:00
William Douglas
0066ddefe1 devices: Add utility functions for the serial output buffer
In preparation for reorganizing how the serial output is constructed
add methods to the serial devices for setting the out buffer after the
device is created.

Also add a method to enable flushing the output buffer to be used to
write the buffer to the PTY fd once the PTY is writable.

Signed-off-by: William Douglas <william.douglas@intel.com>
2021-09-27 14:18:21 +01:00
Michael Zhao
f9dd0aaf8a scripts: Optimize EDK2 building on AArch64
In integration test, we fetch latest EDK2 code on its master branch and
build. While the update on EDK2 master is frequent. And the building is
time consuming. It takes a lot of time in CI and local test. Floating on
top of a busy master branch also bring potential risk in tracking and
debugging.

Now that Cloud Hypervisor support in EDK2 has been steady, we can pin
the EDK2 software versions to avoid unnecessary updating and building.
We can update the versions manually every after several months.

The commit also optimizes the build process by applying multi-threaded
compiling.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-27 17:58:16 +08:00
Michael Zhao
8b7880160e scripts: Refactor the bash code for building linux
Simplified the bash code of building custom linux in integration test.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-27 17:58:16 +08:00
Michael Zhao
b7cb6257b5 scripts: Add a bash function to sync external code
Added a bash function in integration test script to checkout source code
of a GIT repo with specified branch and commit.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-27 17:58:16 +08:00
Henry Wang
6037c83585 resources: Add autotools and texinfo for AArch64
These packages will be used to compile `stress` from source, and
the `stress` will be used by the virtio-balloon integration test.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2021-09-27 17:34:29 +08:00
Sebastien Boeuf
b910a7922d vmm: Fix migration when writing/reading big chunks of data
Both read_exact_from() and write_all_to() functions from the GuestMemory
trait implementation in vm-memory are buggy. They should retry until
they wrote or read the amount of data that was expected, but instead
they simply return an error when this happens. This causes the migration
to fail when trying to send important amount of data through the
migration socket, due to large memory regions.

This should be eventually fixed in vm-memory, and here is the link to
follow up on the issue: https://github.com/rust-vmm/vm-memory/issues/174

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-27 11:13:56 +02:00
Rob Bradford
ad6dfc5875 build: Temporarily use git version of cargo-fuzz in GH action
This resolves issues between released version of cargo fuzz and nightly.

See rust-fuzz/cargo-fuzz#276

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-27 17:08:43 +08:00
dependabot[bot]
cb59976c68 build: bump syn from 1.0.76 to 1.0.77 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.76 to 1.0.77.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.76...1.0.77)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-27 03:01:45 +00:00
dependabot[bot]
520f54cb8d build: bump syn from 1.0.76 to 1.0.77
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.76 to 1.0.77.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.76...1.0.77)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 09:56:54 +00:00
Rob Bradford
1a2d0e6dd8 build: bump linux-loader from 0.3.0 to 0.4.0
Requires manual change to command line loading.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-24 09:11:57 +00:00
Michael Zhao
7383087230 tests: Enable virtio-iommu test on AArch64
Refactored the test case `test_virtio_iommu` to adapt architectures and
different choices among ACPI and FDT. In the case of ACPI, a Focal image
with modified kernel is tested.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-24 07:57:57 +01:00
Michael Zhao
d72af85c42 vmm: Add "_CCA" field to ACPI DSDT table
"_CCA" is required by DMA configuration on AArch64.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-24 07:57:57 +01:00
Michael Zhao
d76d04e2f2 scripts: Prepare a Focal image with custom kernel
On AArch64, ACPI must work with UEFI (EDK2). This way, the kernel is
always loaded from the disk image. We can not specify a direct custom
kernel while using ACPI.

To use a custom kernel, we have to replace the kernel file in the disk
image by:
- Making a copy of the Focal `raw` image
- Mounting the rootfs with `libguestfs-tools`
- Replacing the compressed kernel file

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-24 07:57:57 +01:00
Michael Zhao
56c26b3d9c resource: Install libguestfs-tools in Docker image
Installed `libguestfs-tools` to replace kernel file in cloud image.
Installed a kernel as `libguestfs-tools` requires.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-23 08:59:58 +01:00
dependabot[bot]
2280be825e build: bump openssl-sys from 0.9.66 to 0.9.67
Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.66 to 0.9.67.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.66...openssl-sys-v0.9.67)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-22 08:00:42 +00:00
dependabot[bot]
73c822f64a build: bump vm-fdt from 06cbff3 to ddb3fad
Bumps [vm-fdt](https://github.com/rust-vmm/vm-fdt) from `06cbff3` to `ddb3fad`.
- [Release notes](https://github.com/rust-vmm/vm-fdt/releases)
- [Commits](06cbff3a02...ddb3fad524)

---
updated-dependencies:
- dependency-name: vm-fdt
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-21 15:47:15 +00:00
Rob Bradford
43365ade2e vmm, pci: Implement virtio-mem support for vfio-user
Implement the infrastructure that lets a virtio-mem device map the guest
memory into the device. This is necessary since with virtio-mem zones
memory can be added or removed and the vfio-user device must be
informed.

Fixes: #3025

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-21 15:42:49 +01:00
Rob Bradford
e9d67dc405 vmm: pci: Move creation of vfio_user::Client to DeviceManager
By moving this from the VfioUserPciDevice to DeviceManager the client
can be reused for handling DMA mapping behind an IOMMU.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-21 15:42:49 +01:00
Rob Bradford
fd4f32fa69 virtio-mem: Support multiple mappings
For vfio-user the mapping handler is per device and needs to be removed
when the device in unplugged.

For VFIO the mapping handler is for the default VFIO container (used
when no vIOMMU is used - using a vIOMMU does not require mappings with
virtio-mem)

To represent these two use cases use an enum for the handlers that are
stored.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-21 15:42:49 +01:00
Sebastien Boeuf
6fb88c3c5a virtio-devices: balloon: Add snapshot/restore support
Adding the snapshot/restore support along with migration as well,
allowing a VM with a virtio-balloon device attached to be properly
migrated.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-21 14:47:17 +02:00
Bo Chen
d6c08d902b ci: Use the pre-installed virtiofsd
Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-09-20 16:47:28 +01:00
Wei Liu
86afa38c64 hypervisor: mshv: drop one unsafe in code
The binding already provides a default() method which does the same
thing.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2021-09-20 17:22:31 +02:00
Bo Chen
ae68c802bd Dockerfile: Build and install virtiofsd to the docker image
Given the 'virtiofsd' executable is used in multiple CI workers,
installing them directly to the docker image is more efficient and can
save CI time.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-09-20 13:15:52 +01:00
dependabot[bot]
ccced2ebf4 build: bump arc-swap from 1.3.2 to 1.4.0 in /fuzz
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.3.2 to 1.4.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.3.2...v1.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-19 17:41:20 +00:00
dependabot[bot]
d826b4fbdc build: bump arc-swap from 1.3.2 to 1.4.0
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.3.2 to 1.4.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.3.2...v1.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-19 17:12:50 +00:00
Rob Bradford
0faa7afac2 vmm: Add fast path for PCI config IO port
Looking up devices on the port I/O bus is time consuming during the
boot at there is an O(lg n) tree lookup and the overhead from taking a
lock on the bus contents.

Avoid this by adding a fast path uses the hardcoded port address and
size and directs PCI config requests directly to the device.

Command line:
target/release/cloud-hypervisor --kernel ~/src/linux/vmlinux --cmdline "root=/dev/vda1 console=ttyS0" --serial tty --console off --disk path=~/workloads/focal-server-cloudimg-amd64-custom-20210609-0.raw --api-socket /tmp/api

PIO exit: 17913
PCI fast path: 17871
Percentage on fast path: 99.8%

perf before:

marvin:~/src/cloud-hypervisor (main *)$ perf report -g | grep resolve
     6.20%     6.20%  vcpu0            cloud-hypervisor    [.] vm_device::bus::Bus::resolve

perf after:

marvin:~/src/cloud-hypervisor (2021-09-17-ioapic-fast-path *)$ perf report -g | grep resolve
     0.08%     0.08%  vcpu0            cloud-hypervisor    [.] vm_device::bus::Bus::resolve

The compromise required to implement this fast path is bringing the
creation of the PciConfigIo device into the DeviceManager::new() so that
it can be used in the VmmOps struct which is created before
DeviceManager::create_devices() is called.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-17 17:09:45 +01:00
Michael Zhao
da8eecc797 docs: Describe about virtio-iommu with FDT
Added a section in "Usage" chapter of "iommu.md" to introduce the
special behavior when virtio-iommu is working with FDT on AArch64.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-17 12:19:46 +02:00
Michael Zhao
9dc9e224b9 tests: Enable IOMMU test case on AArch64
For AArch64, now virtual IOMMU is only tested on FDT, not ACPI.
In the case of FDT, the behavior of IOMMU is a bit different with ACPI.
All the devices on the PCI bus will be attached to the virtual IOMMU,
except the virtio-iommu device itself. So these devices will all be
added to IOMMU groups, and appear in folder '/sys/kernel/iommu_groups/'.

The result is, on AArch64 IOMMU group '0' contains "0000:00:01.0" which
is the console device. But on X86, console device is not attached to
IOMMU. So the IOMMU group '0' contains "0000:00:02.0" which is the first
disk.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-17 12:19:46 +02:00
Michael Zhao
b3fa56544c virtio-devices: iommu: Support AArch64
The MSI IOVA address on X86 and AArch64 is different.

This commit refactored the code to receive the MSI IOVA address and size
from device_manager, which provides the actual IOVA space data for both
architectures.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-17 12:19:46 +02:00
Michael Zhao
b30ddc0837 aarch64: Refactor AArch64 GIC space definitions
Move the definition of MSI space to layout.rs, so other crates can
reference it. Now it is needed by virtio-iommu.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-17 12:19:46 +02:00
Michael Zhao
253c06d3ba arch/aarch64: Add virtio-iommu device in FDT
Add a virtio-iommu node into FDT if iommu option is turned on. Now we
support only one virtio-iommu device.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2021-09-17 12:19:46 +02:00
William Douglas
46f6d9597d vmm: Switch to using the serial_manager for serial input
This change switches from handling serial input in the VMM thread to
its own thread controlled by the SerialManager.

The motivation for this change is to avoid the VMM thread being unable
to process events while serial input is happening and vice versa.

The change also makes future work flushing the serial buffer on PTY
connections easier.

Signed-off-by: William Douglas <william.douglas@intel.com>
2021-09-17 11:15:35 +01:00
William Douglas
7b4f56e372 vmm: Add new serial_manager for serial input handling
This change adds a SerialManager with its own epoll handling that
should be created and run by the DeviceManager when creating an
appropriately configured console (serial tty or pty).

Both stdin and pty input are handled by the SerialManager. The stdin
and pty specific methods used by the VMM should be removed in a future
commit.

Signed-off-by: William Douglas <william.douglas@intel.com>
2021-09-17 11:15:35 +01:00
William Douglas
d6a2f48b32 vmm: device_manager: Make PtyPair implement Clone
The clone method for PtyPair should have been an impl of the Clone
trait but the method ended up not being used. Future work will make
use of the trait however so correct the missing trait implementation.

Signed-off-by: William Douglas <william.douglas@intel.com>
2021-09-17 11:15:35 +01:00
Hui Zhu
c313bcbfd4 net_util: Change libc::getrandom to getrandom::getrandom
libc::getrandom need to be called inside unsafe and it is not
cross-platform friendly.
Change it to getrandom::getrandom that is safe and cross-platform
friendly.

Signed-off-by: Hui Zhu <teawater@antfin.com>
2021-09-17 09:24:10 +02:00
dependabot[bot]
c741c01cc0 build: bump unicode-width from 0.1.8 to 0.1.9 in /fuzz
Bumps [unicode-width](https://github.com/unicode-rs/unicode-width) from 0.1.8 to 0.1.9.
- [Release notes](https://github.com/unicode-rs/unicode-width/releases)
- [Commits](https://github.com/unicode-rs/unicode-width/compare/v0.1.8...v0.1.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-17 00:29:15 +00:00
dependabot[bot]
0aba41b3ee build: bump unicode-width from 0.1.8 to 0.1.9
Bumps [unicode-width](https://github.com/unicode-rs/unicode-width) from 0.1.8 to 0.1.9.
- [Release notes](https://github.com/unicode-rs/unicode-width/releases)
- [Commits](https://github.com/unicode-rs/unicode-width/compare/v0.1.8...v0.1.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-16 23:38:40 +00:00
dependabot[bot]
f67b3f79ea build: bump vmm-sys-util from 0.8.0 to 0.9.0
Bumps [vmm-sys-util](https://github.com/rust-vmm/vmm-sys-util) from 0.8.0 to 0.9.0.
- [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.8.0...v0.9.0)

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

This needed a bunch of manual updates as well, including vfio-ioctls and
vhost crates. The vhost crate is being patched with the latest version
from rust-vmm because the version 0.1.0 on crates.io doesn't include the
patches we need yet.

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-16 14:01:19 +01:00
Sebastien Boeuf
02173f42fc deps: Update kvm-ioctls to 0.10.0
Updating kvm-ioctls from 0.9.0 to 0.10.0 now that Cloud Hypervisor
relies on kvm-bindings 0.5.0.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-16 12:53:05 +01:00
dependabot[bot]
8ea0c542fd build: bump dirs from 3.0.2 to 4.0.0
Bumps [dirs](https://github.com/soc/dirs-rs) from 3.0.2 to 4.0.0.
- [Release notes](https://github.com/soc/dirs-rs/releases)
- [Commits](https://github.com/soc/dirs-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-15 23:39:31 +00:00
dependabot[bot]
c1e896dddb build: bump libc from 0.2.101 to 0.2.102
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.101 to 0.2.102.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.101...0.2.102)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-15 17:23:46 +00:00
Sebastien Boeuf
a6040d7a30 vmm: Create a single VFIO container
For most use cases, there is no need to create multiple VFIO containers
as it causes unwanted behaviors. Especially when passing multiple
devices from the same IOMMU group, we need to use the same container so
that it can properly list the groups that have been already opened. The
correct logic was already there in vfio-ioctls, but it was incorrectly
used from our VMM implementation.

For the special case where we put a VFIO device behind a vIOMMU, we must
create one container per device, as we need to control the DMA mappings
per device, which is performed at the container level. Because we must
keep one container per device, the vIOMMU use case prevents multiple
devices attached to the same IOMMU group to be passed through the VM.
But this is a limitation that we are fine with, especially since the
vIOMMU doesn't let us group multiple devices in the same group from a
guest perspective.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-15 09:08:13 -07:00
dependabot[bot]
a5d77cdee9 build: bump libc from 0.2.101 to 0.2.102 in /fuzz
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.101 to 0.2.102.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.101...0.2.102)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-15 16:06:46 +00:00
Rob Bradford
34f220edcd main: Don't panic() if blocking signals fails
This allows Cloud Hypervisor to be run under `perf` as some of the
signals will already be blocked in the child process.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-15 16:20:28 +01:00
Sebastien Boeuf
bcdac10149 deps: Bump kvm-bindings to v0.5.0
Update the kvm-bindings dependency so that Cloud Hypervisor now depends
on the version 0.5.0, which is based on Linux kernel v5.13.0. We still
have to rely on a forked version to be able to serialize all the KVM
structures we need.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2021-09-15 16:20:17 +01:00
Rob Bradford
ccda1a004e devices: cmos: Increase robustness of CMOS device
Check sizes of data reads/writes to avoid panics.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-15 09:40:20 +02:00
Rob Bradford
43f0dd6d25 devices: ioapic: Increase robustness of IOAPIC operations
Validate the size of I/O reads and check that no request is made to an
out of bounds index (which would cause a panic.)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-15 09:40:20 +02:00
Rob Bradford
a77160dca4 devices: acpi: Increase robustness of bus devices
Check the size of data buffer for reading on the ApciPmTimer device to
avoid a potential panic if the guest uses non-DWORD access.

Simplify the zeroring of the buffer for AcpiShutdownDevice.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-15 09:40:20 +02:00
dependabot[bot]
1d78812b63 build: bump serde_json from 1.0.67 to 1.0.68 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.67 to 1.0.68.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.67...v1.0.68)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-15 00:06:30 +00:00
dependabot[bot]
8836715c2d build: bump serde_json from 1.0.67 to 1.0.68
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.67 to 1.0.68.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.67...v1.0.68)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-15 00:06:23 +00:00
Alyssa Ross
330b5ea3be vmm: notify virtio-console of pty resizes
When a pty is resized (using the TIOCSWINSZ ioctl -- see ioctl_tty(2)),
the kernel will send a SIGWINCH signal to the pty's foreground process
group to notify it of the resize.  This is the only way to be notified
by the kernel of a pty resize.

We can't just make the cloud-hypervisor process's process group the
foreground process group though, because a process can only set the
foreground process group of its controlling terminal, and
cloud-hypervisor's controlling terminal will often be the terminal the
user is running it in.  To work around this, we fork a subprocess in a
new process group, and set its process group to be the foreground
process group of the pty.  The subprocess additionally must be running
in a new session so that it can have a different controlling
terminal.  This subprocess writes a byte to a pipe every time the pty
is resized, and the virtio-console device can listen for this in its
epoll loop.

Alternatives I considered were to have the subprocess just send
SIGWINCH to its parent, and to use an eventfd instead of a pipe.
I decided against the signal approach because re-purposing a signal
that has a very specific meaning (even if this use was only slightly
different to its normal meaning) felt unclean, and because it would
have required using pidfds to avoid race conditions if
cloud-hypervisor had terminated, which added complexity.  I decided
against using an eventfd because using a pipe instead allows the child
to be notified (via poll(2)) when nothing is reading from the pipe any
more, meaning it can be reliably notified of parent death and
terminate itself immediately.

I used clone3(2) instead of fork(2) because without
CLONE_CLEAR_SIGHAND the subprocess would inherit signal-hook's signal
handlers, and there's no other straightforward way to restore all signal
handlers to their defaults in the child process.  The only way to do
it would be to iterate through all possible signals, or maintain a
global list of monitored signals ourselves (vmm:vm::HANDLED_SIGNALS is
insufficient because it doesn't take into account e.g. the SIGSYS
signal handler that catches seccomp violations).

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2021-09-14 15:43:25 +01:00
Alyssa Ross
98bfd1e988 virtio-devices: get tty size from the right tty
Previously, we were always getting the size from stdin, even when the
console was hooked up to a pty.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2021-09-14 15:43:25 +01:00
Alyssa Ross
28382a1491 virtio-devices: determine tty size in console
This prepares us to be able to handle console resizes in the console
device's epoll loop, which we'll have to do if the output is a pty,
since we won't get SIGWINCH from it.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2021-09-14 15:43:25 +01:00
dependabot[bot]
68e6a14deb build: bump anyhow from 1.0.43 to 1.0.44 in /fuzz
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.43 to 1.0.44.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.43...1.0.44)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-14 00:54:59 +00:00
dependabot[bot]
f3778a7fc7 build: bump anyhow from 1.0.43 to 1.0.44
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.43 to 1.0.44.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.43...1.0.44)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-14 00:22:00 +00:00
dependabot[bot]
c6a110dd28 build: bump mshv-bindings from b01bbf8 to 0b58354
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `b01bbf8` to `0b58354`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](b01bbf8f6e...0b5835475c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-13 23:36:12 +00:00
dependabot[bot]
b0c7df2e59 build: bump vfio-ioctls from a8ee64b to 06be730
Bumps [vfio-ioctls](https://github.com/rust-vmm/vfio-ioctls) from `a8ee64b` to `06be730`.
- [Release notes](https://github.com/rust-vmm/vfio-ioctls/releases)
- [Commits](a8ee64b978...06be730ff1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-11 17:43:43 +00:00
dependabot[bot]
1067059c4a build: bump mshv-ioctls from 0d6e4e8 to b01bbf8
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `0d6e4e8` to `b01bbf8`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](0d6e4e82b9...b01bbf8f6e)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-11 17:14:05 +00:00
Alyssa Ross
8abe8c679b seccomp: allow mmap everywhere brk is allowed
Musl often uses mmap to allocate memory where Glibc would use brk.
This has caused seccomp violations for me on the API and signal
handling threads.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2021-09-10 12:01:31 -07:00
Rob Bradford
b6b686c71c vmm: Shutdown VMM if API thread panics
See: #3031

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-10 10:52:08 -07:00
Rob Bradford
171d12943d vmm: memory_manager: Increase robustness of MemoryManager control device
See: #1289

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-10 10:23:19 -07:00
Rob Bradford
bdc44cd8bc vmm: cpu: Increase robustness of CpuManager control device
See: #1289

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-10 10:22:05 -07:00
Rob Bradford
33a55bac0f virtio-devices: seccomp: Split out common seccomp rules
As well as reducing the amount of code this also improves the binary
size slightly:

cargo bloat --release -n 2000 --bin cloud-hypervisor | grep virtio_devices::seccomp_filters::get_seccomp_rules

Before:
 0.1%   0.2%   7.8KiB       virtio_devices virtio_devices::seccomp_filters::get_seccomp_rules
After:
 0.0%   0.1%   3.0KiB       virtio_devices virtio_devices::seccomp_filters::get_seccomp_rules

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-10 10:11:12 -07:00
Rob Bradford
82ace6e327 build: Update version of toolchain in container
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-10 10:10:11 -07:00
Bo Chen
2e56f0df77 ci: Rustify ovs-dpdk setup and cleanup
Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-09-10 07:41:15 +01:00
Bo Chen
a181b77bc8 ci: Add integration test for live migration with OVS-DPDK
Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-09-10 07:41:15 +01:00
Bo Chen
9023412e31 tests: Refactor test_ovs_dpdk
This patch adds a separate function to launch two guest VMs and ensure
they are connected through ovs-dpdk, so that we can reuse this function
in other tests, e.g. the test for live-migration with ovs-dpdk.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2021-09-10 07:41:15 +01:00
87 changed files with 4105 additions and 2059 deletions

18
.github/workflows/dco.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: DCO
on:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Check DCO
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pip3 install -U dco-check
dco-check

View File

@@ -22,6 +22,8 @@ jobs:
target: ${{ matrix.target }}
override: true
- name: Install Cargo fuzz
run: cargo install -f cargo-fuzz
# Temporary fix for cargo-fuzz on latest nightly: https://github.com/rust-fuzz/cargo-fuzz/issues/276
#run: cargo install cargo-fuzz
run: cargo install --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
- name: Cargo Fuzz Build
run: cargo fuzz build

184
Cargo.lock generated
View File

@@ -44,9 +44,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.43"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
[[package]]
name = "api_client"
@@ -57,9 +57,9 @@ dependencies = [
[[package]]
name = "arc-swap"
version = "1.3.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63"
[[package]]
name = "arch"
@@ -74,6 +74,7 @@ dependencies = [
"linux-loader",
"log",
"serde",
"serde_derive",
"thiserror",
"versionize",
"versionize_derive",
@@ -108,7 +109,7 @@ checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
dependencies = [
"addr2line",
"cc",
"cfg-if 1.0.0",
"cfg-if",
"libc",
"miniz_oxide",
"object",
@@ -156,15 +157,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.70"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
@@ -190,13 +185,13 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "18.0.0"
version = "19.0.0"
dependencies = [
"anyhow",
"api_client",
"clap",
"credibility",
"dirs",
"dirs 4.0.0",
"epoll",
"event_monitor",
"hypervisor",
@@ -216,15 +211,6 @@ dependencies = [
"wait-timeout",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "crc32c"
version = "0.6.0"
@@ -279,6 +265,15 @@ dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.6"
@@ -357,7 +352,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"wasi",
]
@@ -413,14 +408,23 @@ dependencies = [
[[package]]
name = "iced-x86"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
dependencies = [
"lazy_static",
"static_assertions",
]
[[package]]
name = "instant"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
dependencies = [
"cfg-if",
]
[[package]]
name = "io-uring"
version = "0.5.2"
@@ -448,8 +452,8 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "kvm-bindings"
version = "0.4.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.4.0#1a68725639283e622f4bb64584885b30bfe8be44"
version = "0.5.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
dependencies = [
"serde",
"serde_derive",
@@ -458,9 +462,9 @@ dependencies = [
[[package]]
name = "kvm-ioctls"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2924454e22895c738e43331ae310459c74a11ded9c97dc250129ee10d2f9ca2"
checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76"
dependencies = [
"kvm-bindings",
"libc",
@@ -475,15 +479,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "libssh2-sys"
version = "0.2.21"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee"
checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca"
dependencies = [
"cc",
"libc",
@@ -507,18 +511,18 @@ dependencies = [
[[package]]
name = "linux-loader"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c819cc8275b0f2c1ed9feec455ca288b45d82932384a6a5f7a86812ee3427459"
checksum = "8a5e77493808403a6bd56a301a64ea6b9342e36ea845044bf0dfdf56fe52fa08"
dependencies = [
"vm-memory",
]
[[package]]
name = "lock_api"
version = "0.3.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
@@ -529,7 +533,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@@ -560,7 +564,7 @@ dependencies = [
[[package]]
name = "mshv-bindings"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
source = "git+https://github.com/rust-vmm/mshv?branch=main#99da566389546aedb56fc3d279e01c5dbde79bce"
dependencies = [
"libc",
"serde",
@@ -572,7 +576,7 @@ dependencies = [
[[package]]
name = "mshv-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
source = "git+https://github.com/rust-vmm/mshv?branch=main#99da566389546aedb56fc3d279e01c5dbde79bce"
dependencies = [
"libc",
"mshv-bindings",
@@ -591,6 +595,7 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom",
"lazy_static",
"libc",
"log",
@@ -618,9 +623,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.66"
version = "0.9.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82"
checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058"
dependencies = [
"autocfg",
"cc",
@@ -635,24 +640,25 @@ version = "0.1.0"
[[package]]
name = "parking_lot"
version = "0.10.2"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.7.2"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 0.1.10",
"cloudabi",
"cfg-if",
"instant",
"libc",
"redox_syscall 0.1.57",
"redox_syscall",
"smallvec",
"winapi",
]
@@ -681,9 +687,9 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.19"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
[[package]]
name = "pnet"
@@ -775,9 +781,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
dependencies = [
"unicode-xid",
]
@@ -795,9 +801,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@@ -811,12 +817,6 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_syscall"
version = "0.2.10"
@@ -833,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall 0.2.10",
"redox_syscall",
]
[[package]]
@@ -893,8 +893,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "seccompiler"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68"
dependencies = [
"libc",
]
@@ -933,9 +934,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.67"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
@@ -963,15 +964,15 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "ssh2"
version = "0.9.1"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d876d4d57f6bbf2245d43f7ec53759461f801a446d3693704aa6d27b257844d7"
checksum = "269343e64430067a14937ae0e3c4ec604c178fb896dde0964b1acd22b3e2eeb1"
dependencies = [
"bitflags",
"libc",
@@ -993,9 +994,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.76"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
@@ -1004,9 +1005,9 @@ dependencies = [
[[package]]
name = "synstructure"
version = "0.12.5"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
@@ -1037,7 +1038,7 @@ dependencies = [
name = "test_infra"
version = "0.1.0"
dependencies = [
"dirs",
"dirs 3.0.2",
"epoll",
"libc",
"ssh2",
@@ -1057,18 +1058,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -1077,9 +1078,9 @@ dependencies = [
[[package]]
name = "unicode-width"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
@@ -1147,7 +1148,7 @@ dependencies = [
[[package]]
name = "vfio-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#d51c1fad37be30c20385c55a217e2d90972ea31d"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -1192,9 +1193,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
dependencies = [
"bitflags",
"libc",
@@ -1318,7 +1319,7 @@ dependencies = [
[[package]]
name = "vm-fdt"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#06cbff3a0248ec654467a87b1be7c0bcf78a41a8"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#9c2b252dc19f0e87546e4f7577eaf398f8e3c66a"
[[package]]
name = "vm-memory"
@@ -1389,6 +1390,7 @@ dependencies = [
"versionize",
"versionize_derive",
"vfio-ioctls",
"vfio_user",
"vhdx",
"virtio-devices",
"vm-allocator",
@@ -1401,9 +1403,9 @@ dependencies = [
[[package]]
name = "vmm-sys-util"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cf11afbc4ebc0d5c7a7748a77d19e2042677fc15faa2f4ccccb27c18a60605"
checksum = "733537bded03aaa93543f785ae997727b30d1d9f4a03b7861d23290474242e11"
dependencies = [
"bitflags",
"libc",
@@ -1459,9 +1461,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zerocopy"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2"
checksum = "ae0f717764196a220d8c58500e3a3595e2c9054f95d66267f9fd5f6e74ad0fec"
dependencies = [
"byteorder",
"zerocopy-derive",

View File

@@ -1,6 +1,6 @@
[package]
name = "cloud-hypervisor"
version = "18.0.0"
version = "19.0.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
default-run = "cloud-hypervisor"
@@ -13,21 +13,21 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
lto = true
[dependencies]
anyhow = "1.0.43"
anyhow = "1.0.44"
api_client = { path = "api_client" }
clap = { version = "2.33.3", features = ["wrap_help"] }
epoll = "4.3.1"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = "0.2.101"
libc = "0.2.103"
log = { version = "0.4.14", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
serde_json = "1.0.67"
seccompiler = "0.2.0"
serde_json = "1.0.68"
signal-hook = "0.3.10"
thiserror = "1.0.29"
thiserror = "1.0.30"
vmm = { path = "vmm" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"
vm-memory = "0.6.0"
[build-dependencies]
@@ -35,20 +35,20 @@ clap = { version = "2.33.3", features = ["wrap_help"] }
# List of patched crates
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
[dev-dependencies]
credibility = "0.1.3"
dirs = "3.0.2"
dirs = "4.0.0"
lazy_static= "1.4.0"
net_util = { path = "net_util" }
serde_json = "1.0.67"
serde_json = "1.0.68"
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"
[features]
default = ["acpi", "cmos", "io_uring", "kvm"]
default = ["common", "kvm"]
# Common features for all hypervisors
common = ["acpi", "cmos", "fwdebug", "io_uring"]
acpi = ["vmm/acpi"]

2
Jenkinsfile vendored
View File

@@ -228,6 +228,7 @@ pipeline{
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "sudo modprobe openvswitch"
sh "scripts/dev_cli.sh tests --integration-live-migration"
}
}
@@ -236,6 +237,7 @@ pipeline{
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "sudo modprobe openvswitch"
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
}
}

View File

@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
[dependencies]
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -11,19 +11,20 @@ tdx = []
[dependencies]
acpi_tables = { path = "../acpi_tables", optional = true }
anyhow = "1.0.43"
anyhow = "1.0.44"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.101"
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
libc = "0.2.103"
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
log = "0.4.14"
serde = { version = "1.0.130", features = ["rc"] }
thiserror = "1.0.29"
serde_derive = "1.0.130"
thiserror = "1.0.30"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
[target.'cfg(target_arch = "aarch64")'.dependencies]
fdt_parser = { version = "0.1.3", package = 'fdt'}

View File

@@ -35,9 +35,12 @@ const MSI_PHANDLE: u32 = 2;
const CLOCK_PHANDLE: u32 = 3;
// This is a value for uniquely identifying the FDT node containing the gpio controller.
const GPIO_PHANDLE: u32 = 4;
// This is a value for virtio-iommu. Now only one virtio-iommu device is supported.
const VIRTIO_IOMMU_PHANDLE: u32 = 5;
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
// This is a value for uniquely identifying the FDT node containing the first vCPU.
// The last number of vCPU phandle depends on the number of vCPUs.
const FIRST_VCPU_PHANDLE: u32 = 5;
const FIRST_VCPU_PHANDLE: u32 = 6;
// Read the documentation specified when appending the root node to the FDT.
const ADDRESS_CELLS: u32 = 0x2;
@@ -79,7 +82,7 @@ type Result<T> = result::Result<T, Error>;
#[allow(clippy::too_many_arguments)]
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &CStr,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
device_info: &HashMap<(DeviceType, String), T, S>,
@@ -87,6 +90,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
initrd: &Option<InitramfsConfig>,
pci_space_address: &(u64, u64),
numa_nodes: &NumaNodes,
virtio_iommu_bdf: Option<u32>,
) -> FdtWriterResult<Vec<u8>> {
// Allocate stuff necessary for the holding the blob.
let mut fdt = FdtWriter::new().unwrap();
@@ -107,13 +111,18 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
fdt.property_u32("interrupt-parent", GIC_PHANDLE)?;
create_cpu_nodes(&mut fdt, &vcpu_mpidr, vcpu_topology, numa_nodes)?;
create_memory_node(&mut fdt, guest_mem, numa_nodes)?;
create_chosen_node(&mut fdt, cmdline.to_str().unwrap(), initrd)?;
create_chosen_node(&mut fdt, cmdline, initrd)?;
create_gic_node(&mut fdt, gic_device)?;
create_timer_node(&mut fdt)?;
create_clock_node(&mut fdt)?;
create_psci_node(&mut fdt)?;
create_devices_node(&mut fdt, device_info)?;
create_pci_nodes(&mut fdt, pci_space_address.0, pci_space_address.1)?;
create_pci_nodes(
&mut fdt,
pci_space_address.0,
pci_space_address.1,
virtio_iommu_bdf,
)?;
if numa_nodes.len() > 1 {
create_distance_map_node(&mut fdt, numa_nodes)?;
}
@@ -540,6 +549,7 @@ fn create_pci_nodes(
fdt: &mut FdtWriter,
pci_device_base: u64,
pci_device_size: u64,
virtio_iommu_bdf: Option<u32>,
) -> FdtWriterResult<()> {
// Add node for PCIe controller.
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
@@ -603,6 +613,40 @@ fn create_pci_nodes(
fdt.property_null("interrupt-map-mask")?;
fdt.property_null("dma-coherent")?;
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
// for 'iommu-map' attribute setting.
let iommu_map = [
0_u32,
VIRTIO_IOMMU_PHANDLE,
0_u32,
virtio_iommu_bdf,
virtio_iommu_bdf + 1,
VIRTIO_IOMMU_PHANDLE,
virtio_iommu_bdf + 1,
0xffff - virtio_iommu_bdf,
];
fdt.property_array_u32("iommu-map", &iommu_map)?;
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
// for virtio-iommu node settings.
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
fdt.property_u32("#iommu-cells", 1)?;
fdt.property_string("compatible", "virtio,pci-iommu")?;
// 'reg' is a five-cell address encoded as
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
// should be zero.
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
fdt.property_array_u32("reg", &reg)?;
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
fdt.end_node(virtio_iommu_node)?;
}
fdt.end_node(pci_node)?;
Ok(())

View File

@@ -78,23 +78,17 @@ pub mod kvm {
impl VersionMapped for Gicv3State {}
impl KvmGicV3 {
// Unfortunately bindgen omits defines that are based on other defines.
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
pub const SZ_64K: u64 = 0x0001_0000;
const KVM_VGIC_V3_DIST_SIZE: u64 = KvmGicV3::SZ_64K;
const KVM_VGIC_V3_REDIST_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
// Device trees specific constants
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
/// Get the address of the GIC distributor.
pub fn get_dist_addr() -> u64 {
layout::MAPPED_IO_START - KvmGicV3::KVM_VGIC_V3_DIST_SIZE
layout::GIC_V3_DIST_START
}
/// Get the size of the GIC distributor.
pub fn get_dist_size() -> u64 {
KvmGicV3::KVM_VGIC_V3_DIST_SIZE
layout::GIC_V3_DIST_SIZE
}
/// Get the address of the GIC redistributors.
@@ -104,7 +98,7 @@ pub mod kvm {
/// Get the size of the GIC redistributors.
pub fn get_redists_size(vcpu_count: u64) -> u64 {
vcpu_count * KvmGicV3::KVM_VGIC_V3_REDIST_SIZE
vcpu_count * layout::GIC_V3_REDIST_SIZE
}
/// Save the state of GIC.

View File

@@ -13,6 +13,7 @@ pub mod kvm {
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
use crate::aarch64::gic::GicDevice;
use crate::layout;
use anyhow::anyhow;
use hypervisor::kvm::kvm_bindings;
use hypervisor::CpuState;
@@ -179,10 +180,8 @@ pub mod kvm {
impl VersionMapped for Gicv3ItsState {}
impl KvmGicV3Its {
const KVM_VGIC_V3_ITS_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
fn get_msi_size() -> u64 {
KvmGicV3Its::KVM_VGIC_V3_ITS_SIZE
layout::GIC_V3_ITS_SIZE
}
fn get_msi_addr(vcpu_count: u64) -> u64 {

View File

@@ -55,6 +55,17 @@ pub const UEFI_SIZE: u64 = 0x040_0000;
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
pub const MAPPED_IO_START: u64 = 0x0900_0000;
/// See kernel file arch/arm64/include/uapi/asm/kvm.h for the GIC related definitions.
/// 0x08ff_0000 ~ 0x0900_0000 is reserved for GICv3 Distributor
pub const GIC_V3_DIST_SIZE: u64 = 0x01_0000;
pub const GIC_V3_DIST_START: u64 = MAPPED_IO_START - GIC_V3_DIST_SIZE;
/// Below 0x08ff_0000 is reserved for GICv3 Redistributor.
/// The size defined here is for each vcpu.
/// The total size is 'number_of_vcpu * GIC_V3_REDIST_SIZE'
pub const GIC_V3_REDIST_SIZE: u64 = 0x02_0000;
/// Below Redistributor area is GICv3 ITS
pub const GIC_V3_ITS_SIZE: u64 = 0x02_0000;
/// Space 0x0900_0000 ~ 0x0905_0000 is reserved for legacy devices.
pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000;
pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;

View File

@@ -19,7 +19,6 @@ use gic::GicDevice;
use log::{log_enabled, Level};
use std::collections::HashMap;
use std::convert::TryInto;
use std::ffi::CStr;
use std::fmt::Debug;
use std::sync::Arc;
use vm_memory::{
@@ -136,18 +135,19 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
#[allow(clippy::too_many_arguments)]
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline_cstring: &CStr,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
device_info: &HashMap<(DeviceType, String), T, S>,
initrd: &Option<super::InitramfsConfig>,
pci_space_address: &(u64, u64),
virtio_iommu_bdf: Option<u32>,
gic_device: &dyn GicDevice,
numa_nodes: &NumaNodes,
) -> super::Result<()> {
let fdt_final = fdt::create_fdt(
guest_mem,
cmdline_cstring,
cmdline,
vcpu_mpidr,
vcpu_topology,
device_info,
@@ -155,6 +155,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
initrd,
pci_space_address,
numa_nodes,
virtio_iommu_bdf,
)
.map_err(|_| Error::SetupFdt)?;

View File

@@ -10,6 +10,8 @@
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[cfg(target_arch = "x86_64")]
use crate::x86_64::SgxEpcSection;
@@ -17,6 +19,9 @@ use std::collections::BTreeMap;
use std::fmt;
use std::result;
use std::sync::Arc;
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
use vm_migration::VersionMapped;
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
@@ -54,7 +59,7 @@ pub enum Error {
pub type Result<T> = result::Result<T, Error>;
/// Type for memory region types.
#[derive(PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Versionize)]
pub enum RegionType {
/// RAM type
Ram,
@@ -72,6 +77,8 @@ pub enum RegionType {
Reserved,
}
impl VersionMapped for RegionType {}
/// Module for aarch64 related functionality.
#[cfg(target_arch = "aarch64")]
pub mod aarch64;

View File

@@ -60,6 +60,59 @@ impl Default for TdvfSectionType {
}
}
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct TdVmmDataRegion {
pub start_address: u64,
pub length: u64,
pub region_type: TdVmmDataRegionType,
}
unsafe impl ByteValued for TdVmmDataRegion {}
#[repr(u16)]
#[derive(Clone, Copy, Debug)]
pub enum TdVmmDataRegionType {
Signature = 0x0000,
InterfaceVersion = 0x0001,
SystemUuid = 0x0002,
RamSize = 0x0003,
GraphicsEnabled = 0x0004,
SmpCpuCount = 0x0005,
MachineId = 0x0006,
KernelAddress = 0x0007,
KernelSize = 0x0008,
KernelCommandLine = 0x0009,
InitrdAddress = 0x000a,
InitrdSize = 0x000b,
BootDevice = 0x000c,
NumaData = 0x000d,
BootMenu = 0x000e,
MaximumCpuCount = 0x000f,
KernelEntry = 0x0010,
KernelData = 0x0011,
InitrdData = 0x0012,
CommandLineAddress = 0x0013,
CommandLineSize = 0x0014,
CommandLineData = 0x0015,
KernelSetupAddress = 0x0016,
KernelSetupSize = 0x0017,
KernelSetupData = 0x0018,
FileDir = 0x0019,
AcpiTables = 0x8000,
SmbiosTables = 0x8001,
Irq0Override = 0x8002,
E820Table = 0x8003,
HpetData = 0x8004,
Reserved = 0xffff,
}
impl Default for TdVmmDataRegionType {
fn default() -> Self {
TdVmmDataRegionType::Reserved
}
}
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
// The 32-bit offset to the TDVF metadata is located 32 bytes from
// the end of the file.
@@ -120,6 +173,7 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
enum HobType {
Handoff = 0x1,
ResourceDescriptor = 0x3,
GuidExtension = 0x4,
Unused = 0xfffe,
EndOfHobList = 0xffff,
}
@@ -174,6 +228,22 @@ struct HobResourceDescriptor {
}
unsafe impl ByteValued for HobResourceDescriptor {}
#[repr(C)]
#[derive(Copy, Clone, Default, Debug)]
struct HobGuidType {
header: HobHeader,
name: EfiGuid,
}
unsafe impl ByteValued for HobGuidType {}
#[repr(C)]
#[derive(Copy, Clone, Default, Debug)]
struct TdVmmData {
guid_type: HobGuidType,
region: TdVmmDataRegion,
}
unsafe impl ByteValued for TdVmmData {}
pub struct TdHob {
start_offset: u64,
current_offset: u64,
@@ -303,6 +373,38 @@ impl TdHob {
0x403,
)
}
pub fn add_td_vmm_data(
&mut self,
mem: &GuestMemoryMmap,
region: TdVmmDataRegion,
) -> Result<(), TdvfError> {
let td_vmm_data = TdVmmData {
guid_type: HobGuidType {
header: HobHeader {
r#type: HobType::GuidExtension,
length: std::mem::size_of::<TdVmmData>() as u16,
reserved: 0,
},
// TD_VMM_DATA_GUID CF2643E4-C0D3-46FF-0000-72EE623DDE38
name: EfiGuid {
data1: 0xcf26_43e4,
data2: 0xc0d3,
data3: 0x46ff,
data4: [0x00, 0x00, 0x72, 0xee, 0x62, 0x3d, 0xde, 0x38],
},
},
region,
};
info!(
"Writing HOB TD_VMM_DATA {:x} {:x?}",
self.current_offset, td_vmm_data
);
mem.write_obj(td_vmm_data, GuestAddress(self.current_offset))
.map_err(TdvfError::GuestMemoryWriteHob)?;
self.update_offset::<TdVmmData>();
Ok(())
}
}
#[cfg(test)]

View File

@@ -10,15 +10,15 @@ io_uring = []
[dependencies]
io-uring = "0.5.2"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
qcow = { path = "../qcow" }
thiserror = "1.0.29"
thiserror = "1.0.30"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -6,19 +6,19 @@ edition = "2018"
[dependencies]
acpi_tables = { path = "../acpi_tables", optional = true }
anyhow = "1.0.43"
anyhow = "1.0.44"
arch = { path = "../arch" }
bitflags = "1.3.2"
byteorder = "1.4.3"
epoll = "4.3.1"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" }
vm-memory = "0.6.0"
vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"
[features]
default = []

View File

@@ -34,9 +34,7 @@ impl AcpiShutdownDevice {
impl BusDevice for AcpiShutdownDevice {
// Spec has all fields as zero
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
for i in data.iter_mut() {
*i = 0;
}
data.fill(0)
}
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
@@ -191,6 +189,10 @@ impl Default for AcpiPmTimerDevice {
impl BusDevice for AcpiPmTimerDevice {
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
if data.len() != std::mem::size_of::<u32>() {
warn!("Invalid sized read of PM timer: {}", data.len());
return;
}
let now = Instant::now();
let since = now.duration_since(self.start);
let nanos = since.as_nanos();

View File

@@ -149,7 +149,10 @@ impl VersionMapped for IoapicState {}
impl BusDevice for Ioapic {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
assert!(data.len() == 4);
if data.len() != std::mem::size_of::<u32>() {
warn!("Invalid read size on IOAPIC: {}", data.len());
return;
}
debug!("IOAPIC_R @ offset 0x{:x}", offset);
@@ -166,7 +169,10 @@ impl BusDevice for Ioapic {
}
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
assert!(data.len() == 4);
if data.len() != std::mem::size_of::<u32>() {
warn!("Invalid write size on IOAPIC: {}", data.len());
return None;
}
debug!("IOAPIC_W @ offset 0x{:x}", offset);
@@ -226,6 +232,10 @@ impl Ioapic {
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
IOWIN_OFF..=REG_MAX_OFFSET => {
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
if index > NUM_IOAPIC_PINS {
warn!("IOAPIC index out of range: {}", index);
return;
}
if is_high_bits {
self.reg_entries[index] &= 0xffff_ffff;
self.reg_entries[index] |= u64::from(val) << 32;
@@ -259,6 +269,10 @@ impl Ioapic {
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
IOWIN_OFF..=REG_MAX_OFFSET => {
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
if index > NUM_IOAPIC_PINS {
warn!("IOAPIC index out of range: {}", index);
return 0;
}
if is_high_bits {
(self.reg_entries[index] >> 32) as u32
} else {

View File

@@ -51,13 +51,14 @@ impl Cmos {
impl BusDevice for Cmos {
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
if data.len() != 1 {
warn!("Invalid write size on CMOS device: {}", data.len());
return None;
}
match offset {
INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
DATA_OFFSET => self.data[self.index as usize] = data[0],
o => panic!("bad write offset on CMOS device: {}", o),
o => warn!("bad write offset on CMOS device: {}", o),
};
None
}
@@ -69,6 +70,7 @@ impl BusDevice for Cmos {
}
if data.len() != 1 {
warn!("Invalid read size on CMOS device: {}", data.len());
return;
}
@@ -126,7 +128,10 @@ impl BusDevice for Cmos {
}
}
}
o => panic!("bad read offset on CMOS device: {}", o),
o => {
warn!("bad read offset on CMOS device: {}", o);
0
}
}
}
}

View File

@@ -124,6 +124,10 @@ impl Serial {
Self::new(id, interrupt, None)
}
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
self.out = Some(out);
}
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would
/// change.
pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
@@ -134,6 +138,13 @@ impl Serial {
Ok(())
}
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
if let Some(out) = self.out.as_mut() {
out.flush()?;
}
Ok(())
}
fn is_dlab_set(&self) -> bool {
(self.line_control & LCR_DLAB_BIT) != 0
}

View File

@@ -138,6 +138,10 @@ impl Pl011 {
}
}
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
self.out = Some(out);
}
fn state(&self) -> Pl011State {
Pl011State {
flags: self.flags,
@@ -192,6 +196,13 @@ impl Pl011 {
Ok(())
}
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
if let Some(out) = self.out.as_mut() {
out.flush()?;
}
Ok(())
}
fn pl011_get_baudrate(&self) -> u32 {
if self.fbrd == 0 {
return 0;

View File

@@ -159,6 +159,8 @@ 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.
To use PCI device hotplug start the VM with the HTTP server.
```shell

View File

@@ -121,6 +121,29 @@ lspci
00:04.0 Unassigned class [ffff]: Red Hat, Inc. Virtio RNG
```
### Work with FDT on AArch64
On AArch64 architecture, the virtual IOMMU can still be used even if ACPI is not
enabled. But the effect is different with what the aforementioned test showed.
When ACPI is disabled, virtual IOMMU is supported through Flattened Device Tree
(FDT). In this case, the guest kernel can not tell which device should be
IOMMU-attached and which should not. No matter how many devices you attached to
the virtual IOMMU by setting `iommu=on` option, all the devices on the PCI bus
will be attached to the virtual IOMMU (except the IOMMU itself). Each of the
devices will be added into a IOMMU group.
As a result, the directory content of `/sys/kernel/iommu_groups` would be:
```bash
ls /sys/kernel/iommu_groups/0/devices/
0000:00:02.0
ls /sys/kernel/iommu_groups/1/devices/
0000:00:03.0
ls /sys/kernel/iommu_groups/2/devices/
0000:00:04.0
```
## Faster mappings
By default, the guest memory is mapped with 4k pages and no huge pages, which

View File

@@ -13,18 +13,19 @@ easiest way to get started with Cloud-Hypervisor.
struct MemoryConfig {
size: u64,
mergeable: bool,
shared: bool,
hugepages: bool,
hugepage_size: Option<u64>,
hotplug_method: HotplugMethod,
hotplug_size: Option<u64>,
hotplugged_size: Option<u64>,
shared: bool,
hugepages: bool,
hugepage_size: Option<u64>,
prefault: bool,
zones: Option<Vec<MemoryZoneConfig>>,
}
```
```
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off" [default: size=512M]
```
### `size`
@@ -59,46 +60,6 @@ _Example_
--memory size=1G,mergeable=on
```
### `shared`
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
By sharing a memory mapping, one can share the guest RAM with other processes
running on the host. One can use this option when running vhost-user devices
as part of the VM device model, as they will be driven by standalone daemons
needing access to the guest RAM content.
By default this option is turned off, which results in performing `mmap(2)`
with `MAP_PRIVATE` flag.
_Example_
```
--memory size=1G,shared=on
```
### `hugepages` and `hugepage_size`
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
flags. This performs a memory mapping relying on the specified huge page size. If no huge page size is supplied the system's default huge page size is used.
By using hugepages, one can improve the overall performance of the VM, assuming
the guest will allocate hugepages as well. Another interesting use case is VFIO
as it speeds up the VM's boot time since the amount of IOMMU mappings are
reduced.
The user is responsible for ensuring there are sufficient huge pages of the specified size for the VMM to use.
Failure to do so may result in strange VMM behaviour, e.g. error with `ReadKernelImage` is common.
If there is a strange error with `hugepages` enabled, just disable it or check whether there are enough huge pages.
By default this option is turned off.
_Example_
```
--memory size=1G,hugepages=on,hugepage_size=2M
```
### `hotplug_method`
Selects the way of adding and/or removing memory to/from a booted VM.
@@ -144,6 +105,72 @@ _Example_
--memory size=1G,hotplug_method=virtio-mem,hotplug_size=1G,hotplugged_size=512M
```
### `shared`
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
By sharing a memory mapping, one can share the guest RAM with other processes
running on the host. One can use this option when running vhost-user devices
as part of the VM device model, as they will be driven by standalone daemons
needing access to the guest RAM content.
By default this option is turned off, which results in performing `mmap(2)`
with `MAP_PRIVATE` flag.
_Example_
```
--memory size=1G,shared=on
```
### `hugepages` and `hugepage_size`
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
flags. This performs a memory mapping relying on the specified huge page size.
If no huge page size is supplied the system's default huge page size is used.
By using hugepages, one can improve the overall performance of the VM, assuming
the guest will allocate hugepages as well. Another interesting use case is VFIO
as it speeds up the VM's boot time since the amount of IOMMU mappings are
reduced.
The user is responsible for ensuring there are sufficient huge pages of the
specified size for the VMM to use. Failure to do so may result in strange VMM
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
error with `hugepages` enabled, just disable it or check whether there are enough
huge pages.
By default this option is turned off.
_Example_
```
--memory size=1G,hugepages=on,hugepage_size=2M
```
### `prefault`
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
By triggering prefault, one can allocate all required physical memory and create
its page tables while calling `mmap`. With physical memory allocated, the number
of page faults will decrease during running, and performance will also improve.
Note that boot of VM will be slower with `prefault` enabled because of allocating
physical memory and creating page tables in advance, and physical memory of the
specified size will be consumed quickly.
This option only takes effect at boot of VM. There is also a `prefault` option in
restore and its choice will overwrite `prefault` in memory.
By default this option is turned off.
_Example_
```
--memory size=1G,prefault=on
```
## Advanced Parameters
`MemoryZoneConfig` or what is known as `--memory-zone` from the CLI perspective
@@ -157,14 +184,16 @@ struct MemoryZoneConfig {
file: Option<PathBuf>,
shared: bool,
hugepages: bool,
hugepage_size: Option<u64>,
host_numa_node: Option<u32>,
hotplug_size: Option<u64>,
hotplugged_size: Option<u64>,
prefault: bool,
}
```
```
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off"
```
This parameter expects one or more occurences, allowing for a list of memory
@@ -252,24 +281,30 @@ _Example_
--memory-zone id=mem0,size=1G,shared=on
```
### `hugepages`
### `hugepages` and `hugepage_size`
Specifies if the memory zone must be `mmap(2)` with `MAP_HUGETLB` and
`MAP_HUGE_2MB` flags. This performs a memory zone mapping relying on 2MiB
pages instead of the default 4kiB pages.
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
flags. This performs a memory mapping relying on the specified huge page size.
If no huge page size is supplied the system's default huge page size is used.
By using hugepages, one can improve the overall performance of the VM, assuming
the guest will allocate hugepages as well. Another interesting use case is VFIO
as it speeds up the VM's boot time since the amount of IOMMU mappings are
reduced.
The user is responsible for ensuring there are sufficient huge pages of the
specified size for the VMM to use. Failure to do so may result in strange VMM
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
error with `hugepages` enabled, just disable it or check whether there are enough
huge pages.
By default this option is turned off.
_Example_
```
--memory size=0
--memory-zone id=mem0,size=1G,hugepages=on
--memory-zone id=mem0,size=1G,hugepages=on,hugepage_size=2M
```
### `host_numa_node`
@@ -336,6 +371,30 @@ _Example_
--memory-zone id=mem0,size=1G,hotplug_size=1G,hotplugged_size=512M
```
### `prefault`
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
By triggering prefault, one can allocate all required physical memory and create
its page tables while calling `mmap`. With physical memory allocated, the number
of page faults will decrease during running, and performance will also improve.
Note that boot of VM will be slower with `prefault` enabled because of allocating
physical memory and creating page tables in advance, and physical memory of the
specified size will be consumed quickly.
This option only takes effect at boot of VM. There is also a `prefault` option in
restore and its choice will overwrite `prefault` in memory.
By default this option is turned off.
_Example_
```
--memory size=0
--memory-zone id=mem0,size=1G,prefault=on
```
## NUMA settings
`NumaConfig` or what is known as `--numa` from the CLI perspective has been

View File

@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
[dependencies]
libc = "0.2.101"
libc = "0.2.103"
serde = { version = "1.0.130", features = ["rc"] }
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"

85
fuzz/Cargo.lock generated
View File

@@ -20,9 +20,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.43"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
[[package]]
name = "api_client"
@@ -39,9 +39,9 @@ checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
[[package]]
name = "arc-swap"
version = "1.3.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63"
[[package]]
name = "arch"
@@ -56,6 +56,7 @@ dependencies = [
"linux-loader",
"log",
"serde",
"serde_derive",
"thiserror",
"versionize",
"versionize_derive",
@@ -117,9 +118,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.70"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
@@ -145,7 +146,7 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "17.0.0"
version = "18.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -284,9 +285,9 @@ dependencies = [
[[package]]
name = "iced-x86"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
dependencies = [
"lazy_static",
"static_assertions",
@@ -310,8 +311,8 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "kvm-bindings"
version = "0.4.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.4.0#1a68725639283e622f4bb64584885b30bfe8be44"
version = "0.5.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
dependencies = [
"serde",
"serde_derive",
@@ -320,9 +321,9 @@ dependencies = [
[[package]]
name = "kvm-ioctls"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2924454e22895c738e43331ae310459c74a11ded9c97dc250129ee10d2f9ca2"
checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76"
dependencies = [
"kvm-bindings",
"libc",
@@ -337,9 +338,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "libfuzzer-sys"
@@ -354,9 +355,9 @@ dependencies = [
[[package]]
name = "linux-loader"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c819cc8275b0f2c1ed9feec455ca288b45d82932384a6a5f7a86812ee3427459"
checksum = "8a5e77493808403a6bd56a301a64ea6b9342e36ea845044bf0dfdf56fe52fa08"
dependencies = [
"vm-memory",
]
@@ -391,6 +392,7 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom",
"libc",
"log",
"net_gen",
@@ -438,9 +440,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
dependencies = [
"unicode-xid",
]
@@ -458,9 +460,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@@ -502,8 +504,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "seccompiler"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68"
dependencies = [
"libc",
]
@@ -542,9 +545,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.67"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
@@ -584,9 +587,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.76"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
@@ -615,18 +618,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -635,9 +638,9 @@ dependencies = [
[[package]]
name = "unicode-width"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
@@ -699,7 +702,7 @@ dependencies = [
[[package]]
name = "vfio-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#d51c1fad37be30c20385c55a217e2d90972ea31d"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -742,9 +745,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
dependencies = [
"bitflags",
"libc",
@@ -887,6 +890,7 @@ dependencies = [
"versionize",
"versionize_derive",
"vfio-ioctls",
"vfio_user",
"vhdx",
"virtio-devices",
"vm-allocator",
@@ -899,9 +903,9 @@ dependencies = [
[[package]]
name = "vmm-sys-util"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cf11afbc4ebc0d5c7a7748a77d19e2042677fc15faa2f4ccccb27c18a60605"
checksum = "733537bded03aaa93543f785ae997727b30d1d9f4a03b7861d23290474242e11"
dependencies = [
"bitflags",
"libc",
@@ -936,8 +940,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[patch.unused]]
name = "vm-memory"
version = "0.5.0"
source = "git+https://github.com/rust-vmm/vm-memory?rev=5bd7138758183a73ac0da27ce40c004d95f1a7e9#5bd7138758183a73ac0da27ce40c004d95f1a7e9"

View File

@@ -10,13 +10,13 @@ cargo-fuzz = true
[dependencies]
block_util = { path = "../block_util" }
libc = "0.2.101"
libc = "0.2.103"
libfuzzer-sys = "0.4.2"
qcow = { path = "../qcow" }
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
seccompiler = "0.2.0"
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"
vm-virtio = { path = "../vm-virtio" }
vm-memory = "0.6.0"
@@ -24,8 +24,7 @@ vm-memory = "0.6.0"
path = ".."
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
vm-memory = { git = "https://github.com/rust-vmm/vm-memory", rev = "5bd7138758183a73ac0da27ce40c004d95f1a7e9"}
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
# Prevent this from interfering with workspaces

View File

@@ -11,23 +11,23 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = []
[dependencies]
anyhow = "1.0.43"
anyhow = "1.0.44"
epoll = "4.3.1"
thiserror = "1.0.29"
libc = "0.2.101"
thiserror = "1.0.30"
libc = "0.2.103"
log = "0.4.14"
kvm-ioctls = { version = "0.9.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"], optional = true }
kvm-ioctls = { version = "0.10.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", 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.130", features = ["rc"] }
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
version = "1.14.0"
version = "1.15.0"
default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]

View File

@@ -1153,10 +1153,11 @@ impl cpu::Vcpu for KvmVcpu {
// 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);
for i in 0..32 {
state.fp_regs.vregs[i][0] = self
state.fp_regs.vregs[i] = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
.into();
off += mem::size_of::<u128>();
}
@@ -1233,7 +1234,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
state.fp_regs.vregs[i][0],
state.fp_regs.vregs[i] as u64,
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
off += mem::size_of::<u128>();
@@ -1373,8 +1374,8 @@ impl cpu::Vcpu for KvmVcpu {
0x40000020, 0x40000021, 0x40000080, 0x40000081, 0x40000082, 0x40000083, 0x40000084,
0x40000090, 0x40000091, 0x40000092, 0x40000093, 0x40000094, 0x40000095, 0x40000096,
0x40000097, 0x40000098, 0x40000099, 0x4000009a, 0x4000009b, 0x4000009c, 0x4000009d,
0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4, 0x400000b5,
0x400000b6, 0x400000b7,
0x4000009e, 0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4,
0x400000b5, 0x400000b6, 0x400000b7,
];
for index in hyperv_synic_msrs {
let msr = kvm_msr_entry {

View File

@@ -288,9 +288,7 @@ impl cpu::Vcpu for MshvVcpu {
}
#[allow(non_upper_case_globals)]
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
// Safe because this is just only done during initialization.
// TODO don't zero it everytime we enter this function.
let hv_message: hv_message = unsafe { std::mem::zeroed() };
let hv_message: hv_message = hv_message::default();
match self.fd.run(hv_message) {
Ok(x) => match x.header.message_type {
hv_message_type_HVMSG_X64_HALT => {

View File

@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
edition = "2018"
[dependencies]
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -6,7 +6,8 @@ edition = "2018"
[dependencies]
epoll = "4.3.1"
libc = "0.2.101"
getrandom = "0.2"
libc = "0.2.103"
log = "0.4.14"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
@@ -16,9 +17,9 @@ versionize_derive = "0.1.4"
virtio-bindings = "0.1.0"
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"
[dev-dependencies]
lazy_static = "1.4.0"
pnet = "0.28.0"
serde_json = "1.0.67"
serde_json = "1.0.68"

View File

@@ -82,21 +82,12 @@ impl MacAddr {
pub fn local_random() -> MacAddr {
// Generate a fully random MAC
let mut random_bytes = [0u8; MAC_ADDR_LEN];
unsafe {
// Man page says this function will not be interrupted by a signal
// for requests less than 256 bytes
if libc::getrandom(
random_bytes.as_mut_ptr() as *mut _ as *mut libc::c_void,
MAC_ADDR_LEN,
0,
) < 0
{
error!(
"Error populating MAC address with random data: {}",
std::io::Error::last_os_error()
)
}
};
if let Err(e) = getrandom::getrandom(&mut random_bytes) {
error!(
"Error populating MAC address with random data: {}",
e.to_string()
);
}
// Set the first byte to make the OUI a locally administered OUI
random_bytes[0] = 0x2e;

View File

@@ -10,15 +10,15 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.43"
anyhow = "1.0.44"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
vfio_user = { path = "../vfio_user" }
vmm-sys-util = "0.8.0"
libc = "0.2.101"
vmm-sys-util = "0.9.0"
libc = "0.2.103"
log = "0.4.14"
thiserror = "1.0.29"
thiserror = "1.0.30"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" }

View File

@@ -197,8 +197,8 @@ pub struct PciConfigIo {
impl PciConfigIo {
pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
PciConfigIo {
pci_bus,
config_address: 0,
pci_bus,
}
}
@@ -222,6 +222,7 @@ impl PciConfigIo {
}
self.pci_bus
.as_ref()
.lock()
.unwrap()
.devices
@@ -249,7 +250,7 @@ impl PciConfigIo {
return None;
}
let pci_bus = self.pci_bus.lock().unwrap();
let pci_bus = self.pci_bus.as_ref().lock().unwrap();
if let Some(d) = pci_bus.devices.get(&(device as u32)) {
let mut device = d.lock().unwrap();

View File

@@ -26,7 +26,7 @@ pub use self::device::{
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
pub use self::vfio::{VfioPciDevice, VfioPciError};
pub use self::vfio_user::{VfioUserPciDevice, VfioUserPciDeviceError};
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
/// PCI has four interrupt pins A->D.
#[derive(Copy, Clone)]
@@ -42,3 +42,8 @@ impl PciInterruptPin {
self as u32
}
}
#[cfg(target_arch = "x86_64")]
pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
#[cfg(target_arch = "x86_64")]
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;

View File

@@ -11,7 +11,6 @@ use crate::{
use hypervisor::HypervisorVmError;
use std::any::Any;
use std::os::unix::prelude::AsRawFd;
use std::path::Path;
use std::ptr::null_mut;
use std::sync::{Arc, Barrier, Mutex};
use std::u32;
@@ -20,10 +19,14 @@ use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::VfioIrq;
use vfio_user::{Client, Error as VfioUserError};
use vm_allocator::SystemAllocator;
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
use vm_device::BusDevice;
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, GuestUsize};
use vm_memory::{
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
GuestUsize,
};
use vmm_sys_util::eventfd::EventFd;
pub struct VfioUserPciDevice {
@@ -61,12 +64,10 @@ impl PciSubclass for PciVfioUserSubclass {
impl VfioUserPciDevice {
pub fn new(
vm: &Arc<dyn hypervisor::Vm>,
path: &Path,
client: Arc<Mutex<Client>>,
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
) -> Result<Self, VfioUserPciDeviceError> {
let mut client = Client::new(path).map_err(VfioUserPciDeviceError::Client)?;
// This is used for the BAR and capabilities only
let configuration = PciConfiguration::new(
0,
@@ -80,12 +81,15 @@ impl VfioUserPciDevice {
0,
None,
);
if client.resettable() {
client.reset().map_err(VfioUserPciDeviceError::Client)?;
let resettable = client.lock().unwrap().resettable();
if resettable {
client
.lock()
.unwrap()
.reset()
.map_err(VfioUserPciDeviceError::Client)?;
}
let client = Arc::new(Mutex::new(client));
let vfio_wrapper = VfioUserClientWrapper {
client: client.clone(),
};
@@ -483,3 +487,57 @@ impl Drop for VfioUserPciDevice {
}
}
}
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
client: Arc<Mutex<Client>>,
memory: Arc<M>,
}
impl<M: GuestAddressSpace> VfioUserDmaMapping<M> {
pub fn new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self {
Self { client, memory }
}
}
impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMapping<M> {
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
let mem = self.memory.memory();
let guest_addr = GuestAddress(gpa);
let region = mem.find_region(guest_addr);
if let Some(region) = region {
let file_offset = region.file_offset().unwrap();
let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
+ file_offset.start();
self.client
.lock()
.unwrap()
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error mapping region: {}", e),
)
})
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Region not found for 0x{:x}", gpa),
));
}
}
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
self.client
.lock()
.unwrap()
.dma_unmap(iova, size)
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error unmapping region: {}", e),
)
})
}
}

View File

@@ -10,7 +10,7 @@ path = "src/qcow.rs"
[dependencies]
byteorder = "1.4.3"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
remain = "0.2.2"
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2018"
[dependencies]
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -1,3 +1,12 @@
- [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations)
- [Improved TDX support](#improved-tdx-support)
- [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -7,23 +16,23 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [Notable bug fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [Notable bug fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-2)
- [Notable bug fixes](#notable-bug-fixes-3)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-2)
- [Contributors](#contributors-3)
- [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting)
@@ -31,7 +40,7 @@
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations)
- [Contributors](#contributors-3)
- [Contributors](#contributors-4)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -41,7 +50,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-4)
- [Contributors](#contributors-5)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -49,33 +58,33 @@
- [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-5)
- [Contributors](#contributors-6)
- [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-6)
- [Contributors](#contributors-7)
- [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support)
- [`vhost-user` "Self Spawning" Deprecation](#vhost-user-self-spawning-deprecation)
- [`virtio-mmmio` Removal](#virtio-mmmio-removal)
- [`virtio-mmio` Removal](#virtio-mmio-removal)
- [Snapshot/Restore support for ARM64](#snapshotrestore-support-for-arm64)
- [Improved Linux Boot Time](#improved-linux-boot-time)
- [`SIGTERM/SIGINT` Interrupt Signal Handling](#sigtermsigint-interrupt-signal-handling)
- [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-7)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-8)
- [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-8)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-9)
- [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -88,17 +97,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-9)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-10)
- [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-10)
- [Contributors](#contributors-11)
- [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support)
@@ -108,14 +117,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-11)
- [Contributors](#contributors-12)
- [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot)
- [Contributors](#contributors-12)
- [Contributors](#contributors-13)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -123,7 +132,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-13)
- [Contributors](#contributors-14)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -132,7 +141,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-14)
- [Contributors](#contributors-15)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -159,6 +168,69 @@
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v19.0
This release has been tracked through the [v19.0
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/22).
### Improved PTY handling for serial and `virtio-console`
The PTY support for serial has been enhanced with improved buffering when the
the PTY is not yet connected to. Using `virtio-console` with PTY now results in
the console being resized if the PTY window is also resized.
### PCI boot time optimisations
Multiple optimisations have been made to the PCI handling resulting in
significant improvements in the boot time of the guest.
### Improved TDX support
When using the latest TDVF firmware the ACPI tables created by the VMM are now
exposed via the firmware to the guest.
### Live migration enhancements
Live migration support has been enhanced to support migration with `virtio-mem`
based memory hotplug and the `virtio-balloon` device now supports live
migration.
### `virtio-mem` support with `vfio-user`
The use of `vfio-user` userspaces devices can now be used in conjunction with
`virtio-mem` based memory hotplug and unplug.
### AArch64 for `virtio-iommu`
A paravirtualised IOMMU can now be used on the AArch64 platform.
### Notable bug fixes
* ACPI hotplugged memory is correctly restored after a live migration or
snapshot/restore (#3165)
* Multiple devices from the same IOMMU group can be passed through via VFIO
(#3078 #3113)
* Live migration with large blocks of memory was buggy due to an in issue in
the underlying crate (#3157)
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Bo Chen <chen.bo@intel.com>
* Henry Wang <Henry.Wang@arm.com>
* Hui Zhu <teawater@antfin.com>
* Jianyong Wu <jianyong.wu@arm.com>
* Li Yu <liyu.yukiteru@bytedance.com>
* Michael Zhao <michael.zhao@arm.com>
* Muminul Islam <muislam@microsoft.com>
* Rob Bradford <robert.bradford@intel.com>
* Sebastien Boeuf <sebastien.boeuf@intel.com>
* Wei Liu <liuwe@microsoft.com>
* William Douglas <william.douglas@intel.com>
* Yu Li <liyu.yukiteru@bytedance.com>
# v18.0
This release has been tracked through the [v18.0
@@ -629,7 +701,7 @@ Automatically spawning a `vhost-user-net` or `vhost-user-block` backend is now
deprecated. Users of this functionality will receive a warning and should make
adjustments. The functionality will be removed in the next release.
### `virtio-mmmio` Removal
### `virtio-mmio` Removal
Support for using the `virtio-mmio` transport, rather than using PCI, has been
removed. This has been to simplify the code and significantly

View File

@@ -1,7 +1,7 @@
FROM ubuntu:20.04 as dev
ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.54.0"
ARG RUST_TOOLCHAIN="1.55.0"
ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
@@ -59,9 +59,19 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
RUN if [ "$TARGETARCH" = "arm64" ]; then \
# On AArch64, `setcap` binary should be installed via `libcap2-bin`.
# The `setcap` binary is used in integration tests.
# `libguestfs-tools` is used for modifying cloud image kernel, and it requires
# kernel (any version) image in `/boot` and modules in `/lib/modules`.
apt-get update \
&& apt-get -yq upgrade \
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq libcap2-bin \
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
libcap2-bin \
libguestfs-tools \
linux-image-5.8.0-63-generic \
autotools-dev \
autoconf \
automake \
perl \
texinfo \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*; fi
@@ -91,3 +101,26 @@ RUN export ARCH="$(uname -m)" \
RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
&& mkdir $HOME/.cargo \
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
# install virtiofsd
RUN git clone --depth 1 https://gitlab.com/virtio-fs/qemu.git -b qemu5.0-virtiofs-dax \
&& cd qemu \
&& ./configure --prefix=$PWD --target-list=x86_64-softmmu \
&& make virtiofsd -j `nproc` \
&& cp virtiofsd /usr/local/bin \
&& cd .. && rm -rf qemu
# install SPDK NVMe
RUN git clone https://github.com/spdk/spdk \
&& cd spdk \
&& git checkout a827fd7eeca67209d4c0aaad9a3ed55692e7e36e \
&& git submodule update --init \
&& apt-get update \
&& ./scripts/pkgdep.sh \
&& ./configure --with-vfio-user \
&& make -j `nproc` \
&& mkdir /usr/local/bin/spdk-nvme \
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
&& cd .. && rm -rf spdk

View File

@@ -1947,7 +1947,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_DS2404 is not set
# CONFIG_RTC_DRV_EFI is not set
CONFIG_RTC_DRV_EFI=y
# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_M48T86 is not set
# CONFIG_RTC_DRV_M48T35 is not set

View File

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

View File

@@ -243,8 +243,8 @@ cmd_build() {
ensure_latest_ctr
process_volumes_args
if [[ "$hypervisor" != "kvm" ]]; then
die "Hypervisor value must be kvm"
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
die "Hypervisor value must be kvm or mshv"
fi
if [[ "$hypervisor" = "mshv" ]]; then
exported_device="/dev/mshv"
@@ -336,12 +336,14 @@ cmd_tests() {
esac
shift
done
if [[ "$hypervisor" != "kvm" ]]; then
die "Hypervisor value must be kvm"
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
die "Hypervisor value must be kvm or mshv"
fi
if [[ "$hypervisor" = "mshv" ]]; then
exported_device="/dev/mshv"
fi
set -- "$@" '--hypervisor' $hypervisor
ensure_build_dir

View File

@@ -8,70 +8,97 @@ export BUILD_TARGET=${BUILD_TARGET-aarch64-unknown-linux-gnu}
WORKLOADS_DIR="$HOME/workloads"
WORKLOADS_LOCK="$WORKLOADS_DIR/integration_test.lock"
EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
mkdir -p "$WORKLOADS_DIR"
build_edk2() {
EDK2_REPO="https://github.com/tianocore/edk2.git"
EDK2_DIR="edk2"
EDK2_BRANCH="master"
EDK2_PLAT_REPO="https://github.com/tianocore/edk2-platforms.git"
EDK2_PLAT_DIR="edk2-platforms"
ACPICA_REPO="https://github.com/acpica/acpica.git"
ACPICA_DIR="acpica"
# Checkout source code of a GIT repo with specified branch and commit
# Args:
# $1: Target directory
# $2: GIT URL of the repo
# $3: Required branch
# $4: Required commit (optional)
checkout_repo() {
SRC_DIR="$1"
GIT_URL="$2"
GIT_BRANCH="$3"
GIT_COMMIT="$4"
export WORKSPACE="$EDK2_BUILD_DIR"
export PACKAGES_PATH="$WORKSPACE/$EDK2_DIR:$WORKSPACE/$EDK2_PLAT_DIR"
export IASL_PREFIX="$WORKSPACE/acpica/generate/unix/bin/"
cd "$WORKLOADS_DIR"
if [ ! -d "$WORKSPACE" ]; then
mkdir -p "$WORKSPACE"
fi
pushd "$WORKSPACE"
# Check whether the local HEAD commit same as the remote HEAD or not. Remove the folder if they are different.
if [ -d "$EDK2_DIR" ]; then
pushd $EDK2_DIR
# Check whether the local HEAD commit same as the requested commit or not.
# If commit is not specified, compare local HEAD and remote HEAD.
# Remove the folder if there is difference.
if [ -d "$SRC_DIR" ]; then
pushd $SRC_DIR
git fetch
EDK2_LOCAL_HEAD=$(git rev-parse HEAD)
EDK2_REMOTE_HEAD=$(git rev-parse remotes/origin/$EDK2_BRANCH)
SRC_LOCAL_COMMIT=$(git rev-parse HEAD)
if [ -z "$GIT_COMMIT" ]; then
GIT_COMMIT=$(git rev-parse remotes/origin/"$GIT_BRANCH")
fi
popd
if [ "$EDK2_LOCAL_HEAD" != "$EDK2_REMOTE_HEAD" ]; then
# If EDK2 code is out of date, remove and rebuild all
rm -rf "$EDK2_DIR"
rm -rf "$EDK2_PLAT_DIR"
rm -rf "$ACPICA_DIR"
if [ "$SRC_LOCAL_COMMIT" != "$GIT_COMMIT" ]; then
rm -rf "$SRC_DIR"
fi
fi
if [ ! -d "$EDK2_DIR" ]; then
time git clone --depth 1 "$EDK2_REPO" -b "$EDK2_BRANCH" "$EDK2_DIR"
pushd $EDK2_DIR
git submodule update --init
popd
# Checkout the specified branch and commit (if required)
if [ ! -d "$SRC_DIR" ]; then
git clone --depth 1 "$GIT_URL" -b "$GIT_BRANCH" "$SRC_DIR"
if [ "$GIT_COMMIT" ]; then
pushd "$SRC_DIR"
git fetch --depth 1 origin "$GIT_COMMIT"
git reset --hard FETCH_HEAD
popd
fi
fi
}
build_custom_linux() {
SRCDIR=$PWD
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
LINUX_CUSTOM_BRANCH="ch-5.14"
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
cp $SRCDIR/resources/linux-config-aarch64 $LINUX_CUSTOM_DIR/.config
pushd $LINUX_CUSTOM_DIR
time make -j `nproc`
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
popd
}
build_edk2() {
EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
EDK2_REPO="https://github.com/tianocore/edk2.git"
EDK2_DIR="$EDK2_BUILD_DIR/edk2"
EDK2_PLAT_REPO="https://github.com/tianocore/edk2-platforms.git"
EDK2_PLAT_DIR="$EDK2_BUILD_DIR/edk2-platforms"
ACPICA_REPO="https://github.com/acpica/acpica.git"
ACPICA_DIR="$EDK2_BUILD_DIR/acpica"
export WORKSPACE="$EDK2_BUILD_DIR"
export PACKAGES_PATH="$EDK2_DIR:$EDK2_PLAT_DIR"
export IASL_PREFIX="$ACPICA_DIR/generate/unix/bin/"
if [ ! -d "$EDK2_BUILD_DIR" ]; then
mkdir -p "$EDK2_BUILD_DIR"
fi
if [ ! -d "$EDK2_PLAT_DIR" ]; then
time git clone --depth 1 "$EDK2_PLAT_REPO" -b master "$EDK2_PLAT_DIR"
fi
if [ ! -d "$ACPICA_DIR" ]; then
time git clone --depth 1 "$ACPICA_REPO" -b master "$ACPICA_DIR"
fi
make -C "$ACPICA_DIR"/
# Prepare source code
checkout_repo "$EDK2_DIR" "$EDK2_REPO" master "46b4606ba23498d3d0e66b53e498eb3d5d592586"
pushd "$EDK2_DIR"
git submodule update --init
popd
checkout_repo "$EDK2_PLAT_DIR" "$EDK2_PLAT_REPO" master "8227e9e9f6a8aefbd772b40138f835121ccb2307"
checkout_repo "$ACPICA_DIR" "$ACPICA_REPO" master "b9c69f81a05c45611c91ea9cbce8756078d76233"
pushd "$EDK2_BUILD_DIR"
# Build
make -C acpica -j `nproc`
source edk2/edksetup.sh
make -C edk2/BaseTools
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
make -C edk2/BaseTools -j `nproc`
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE -n 0
cp Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd "$WORKLOADS_DIR"
echo "Info: build UEFI successfully"
popd
}
@@ -105,7 +132,7 @@ update_workloads() {
popd
fi
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom.raw"
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw"
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME"
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
@@ -114,9 +141,7 @@ update_workloads() {
popd
fi
# Convert the raw image to qcow2 image to remove compressed blocks from the disk. Therefore letting the
# qcow2 format image can be directly used in the integration test.
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom.qcow2"
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
@@ -159,59 +184,26 @@ update_workloads() {
fi
popd
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
PE_IMAGE="$WORKLOADS_DIR/Image"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
# Build custom kernel for guest VMs
build_custom_linux
build_custom_linux_kernel() {
pushd $LINUX_CUSTOM_DIR
time make -j `nproc`
cp arch/arm64/boot/Image $WORKLOADS_DIR/Image || exit 1
popd
}
SRCDIR=$PWD
LINUX_CUSTOM_BRANCH="ch-5.14"
# Check whether the local HEAD commit same as the remote HEAD or not. Remove the folder if they are different.
if [ -d "$LINUX_CUSTOM_DIR" ]; then
pushd $LINUX_CUSTOM_DIR
git fetch
LINUX_CUSTOM_LOCAL_HEAD=$(git rev-parse HEAD)
LINUX_CUSTOM_REMOTE_HEAD=$(git rev-parse remotes/origin/$LINUX_CUSTOM_BRANCH)
popd
if [ "$LINUX_CUSTOM_LOCAL_HEAD" != "$LINUX_CUSTOM_REMOTE_HEAD" ]; then
rm -rf "$LINUX_CUSTOM_DIR"
fi
fi
if [ ! -d "$LINUX_CUSTOM_DIR" ]; then
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b $LINUX_CUSTOM_BRANCH $LINUX_CUSTOM_DIR
fi
cp $SRCDIR/resources/linux-config-aarch64 $LINUX_CUSTOM_DIR/.config
build_custom_linux_kernel
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
QEMU_DIR="qemu_build"
if [ ! -f "$VIRTIOFSD" ]; then
pushd $WORKLOADS_DIR
git clone --depth 1 "https://gitlab.com/virtio-fs/qemu.git" -b "qemu5.0-virtiofs-dax" $QEMU_DIR
pushd $QEMU_DIR
time ./configure --prefix=$PWD --target-list=aarch64-softmmu
time make virtiofsd -j `nproc`
cp virtiofsd $VIRTIOFSD || exit 1
popd
rm -rf $QEMU_DIR
popd
fi
# Update the kernel in the cloud image for some tests that requires recent kernel version
FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME="focal-server-cloudimg-arm64-custom-20210929-0-update-kernel.raw"
cp "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME" "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME"
FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR="$WORKLOADS_DIR/focal-server-cloudimg-root"
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
# Mount the 'raw' image, replace the compressed kernel file and umount the working folder
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR" || exit 1
cp "$WORKLOADS_DIR"/Image.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
# Build virtiofsd
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
if [ ! -f "$VIRTIOFSD_RS" ]; then
pushd $WORKLOADS_DIR
git clone --depth 1 "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
git checkout c847ab63acabed2ed6e6913b9c76bb5099a1d4cb
pushd $VIRTIOFSD_RS_DIR
time cargo build --release
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
@@ -292,12 +284,8 @@ sudo bash -c "echo 1000000 > /sys/kernel/mm/ksm/pages_to_scan"
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Setup ovs-dpdk
# Setup huge-pages for ovs-dpdk
echo 2048 | sudo tee /proc/sys/vm/nr_hugepages
service openvswitch-switch start
ovs-vsctl init
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
service openvswitch-switch restart
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
time cargo test $features_test "tests::parallel::$test_filter"

View File

@@ -15,6 +15,11 @@ process_common_args "$@"
features_build=""
features_test="--features integration_tests"
if [ "$hypervisor" = "mshv" ] ; then
features_build="--no-default-features --features mshv,common"
features_test="--no-default-features --features mshv,common,integration_tests"
fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
@@ -79,8 +84,11 @@ strip target/$BUILD_TARGET/release/cloud-hypervisor
strip target/$BUILD_TARGET/release/vhost_user_net
strip target/$BUILD_TARGET/release/ch-remote
export RUST_BACKTRACE=1
# Test ovs-dpdk relies on hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
RES=$?

View File

@@ -5,6 +5,12 @@ source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh
process_common_args "$@"
if [[ "$hypervisor" = "mshv" ]]; then
echo "Unsupported SGX test for MSHV"
exit 1
fi
# For now these values are deafult for kvm
features_build=""
features_test="--features integration_tests"

View File

@@ -15,6 +15,11 @@ process_common_args "$@"
features_build=""
features_test="--features integration_tests"
if [ "$hypervisor" = "mshv" ] ; then
features_build="--no-default-features --features mshv,common"
features_test="--no-default-features --features mshv,common,integration_tests"
fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
@@ -118,25 +123,12 @@ if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
QEMU_DIR="qemu_build"
if [ ! -f "$VIRTIOFSD" ]; then
pushd $WORKLOADS_DIR
git clone --depth 1 "https://gitlab.com/virtio-fs/qemu.git" -b "qemu5.0-virtiofs-dax" $QEMU_DIR
pushd $QEMU_DIR
time ./configure --prefix=$PWD --target-list=x86_64-softmmu
time make virtiofsd -j `nproc`
cp virtiofsd $VIRTIOFSD || exit 1
popd
rm -rf $QEMU_DIR
popd
fi
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
if [ ! -f "$VIRTIOFSD_RS" ]; then
pushd $WORKLOADS_DIR
git clone --depth 1 "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
git checkout c847ab63acabed2ed6e6913b9c76bb5099a1d4cb
pushd $VIRTIOFSD_RS_DIR
time cargo build --release
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
@@ -202,12 +194,6 @@ sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
# Setup ovs-dpdk
service openvswitch-switch start
ovs-vsctl init
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
service openvswitch-switch restart
export RUST_BACKTRACE=1
time cargo test $features_test "tests::parallel::$test_filter"
RES=$?

View File

@@ -2,5 +2,5 @@
786fe1c33588334e92b35c65e414da068df180bc bionic-server-cloudimg-arm64.raw
6e66f9f4b01adc72c884c1c1111e60afadc9c871 bionic-server-cloudimg-arm64.qcow2
e4addb6e212a298144f9eb0eb6e36019d013f0e7 alpine-minirootfs-aarch64.tar.gz
063d1a9f32db641138e6e0c53f58e6545a3d48e6 focal-server-cloudimg-arm64-custom.raw
013837926872f1c7d1b3a1a95305e4a31c8600ab focal-server-cloudimg-arm64-custom.qcow2
25b4f9ac308898d63b73d7db0e0e2d4768853723 focal-server-cloudimg-arm64-custom-20210929-0.qcow2
9953b31bb1923cdd8d91b1b7cc9ad3a9be1e0a59 focal-server-cloudimg-arm64-custom-20210929-0.raw

View File

@@ -33,8 +33,7 @@ process_common_args() {
esac
shift
done
if [[ "$hypervisor" != "kvm" ]]; then
echo "Hypervisor value must be kvm"
exit 1
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
die "Hypervisor value must be kvm or mshv"
fi
}

View File

@@ -117,7 +117,8 @@ impl log::Log for Logger {
}
fn prepare_default_values() -> (String, String, String) {
let default_vcpus = format! {"boot={}", config::DEFAULT_VCPUS};
let default_vcpus =
format! {"boot={},max_phys_bits={}", config::DEFAULT_VCPUS,config::DEFAULT_MAX_PHYS_BITS};
let default_memory = format! {"size={}M", config::DEFAULT_MEMORY_MB};
let default_rng = format! {"src={}", config::DEFAULT_RNG_SOURCE};
@@ -163,7 +164,8 @@ fn create_app<'a, 'b>(
hugepages=on|off,hugepage_size=<hugepage_size>,\
hotplug_method=acpi|virtio-mem,\
hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>\"",
hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off\"",
)
.default_value(default_memory)
.group("vm-config"),
@@ -178,7 +180,8 @@ fn create_app<'a, 'b>(
hugepages=on|off,hugepage_size=<hugepage_size>,\
host_numa_node=<node_id>,\
id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>\"",
hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off\"",
)
.takes_value(true)
.min_values(1)
@@ -501,7 +504,9 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
// installing handlers for, to make sure they only ever run on the
// dedicated signal handling thread we'll start in a bit.
for sig in vmm::vm::HANDLED_SIGNALS {
block_signal(sig).unwrap();
if let Err(e) = block_signal(sig) {
eprintln!("Error blocking signals: {}", e);
}
}
event!("vmm", "starting");
@@ -632,7 +637,7 @@ mod unit_tests {
max_vcpus: 1,
topology: None,
kvm_hyperv: false,
max_phys_bits: None,
max_phys_bits: 46,
},
memory: MemoryConfig {
size: 536_870_912,
@@ -642,8 +647,9 @@ mod unit_tests {
hotplugged_size: None,
shared: false,
hugepages: false,
zones: None,
hugepage_size: None,
prefault: false,
zones: None,
},
kernel: Some(KernelConfig {
path: PathBuf::from("/path/to/kernel"),

View File

@@ -9,5 +9,5 @@ dirs = "3.0.1"
epoll = "4.3.1"
libc = "0.2.91"
ssh2 = "0.9.1"
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"
wait-timeout = "0.2.0"

File diff suppressed because it is too large Load Diff

View File

@@ -5,13 +5,13 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
[dependencies]
anyhow = "1.0.43"
libc = "0.2.101"
anyhow = "1.0.44"
libc = "0.2.103"
log = "0.4.14"
serde = {version = ">=1.0.27", features = ["rc"] }
serde_derive = ">=1.0.27"
serde_json = ">=1.0.9"
thiserror = "1.0.29"
thiserror = "1.0.30"
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = ">=0.3.1"

View File

@@ -8,7 +8,7 @@ license = "Apache-2.0"
[dependencies]
byteorder = "1.4.3"
crc32c = "0.6.0"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
remain = "0.2.2"
thiserror = "1.0"

View File

@@ -9,10 +9,10 @@ default = []
[dependencies]
epoll = "4.3.1"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
virtio-bindings = "0.1.0"
vm-memory = { version = "0.6.0", features = ["backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.8.0"
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
vmm-sys-util = "0.9.0"
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }

View File

@@ -9,12 +9,12 @@ block_util = { path = "../block_util" }
clap = { version = "2.33.3", features = ["wrap_help"] }
env_logger = "0.9.0"
epoll = "4.3.1"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
option_parser = { path = "../option_parser" }
qcow = { path = "../qcow" }
vhost_user_backend = { path = "../vhost_user_backend" }
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
virtio-bindings = "0.1.0"
vm-memory = "0.6.0"
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -8,12 +8,12 @@ edition = "2018"
clap = { version = "2.33.3", features = ["wrap_help"] }
env_logger = "0.9.0"
epoll = "4.3.1"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" }
vhost_user_backend = { path = "../vhost_user_backend" }
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
virtio-bindings = "0.1.0"
vm-memory = "0.6.0"
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -10,30 +10,30 @@ io_uring = ["block_util/io_uring"]
mshv = []
[dependencies]
anyhow = "1.0.43"
arc-swap = "1.3.2"
anyhow = "1.0.44"
arc-swap = "1.4.0"
block_util = { path = "../block_util" }
byteorder = "1.4.3"
epoll = "4.3.1"
event_monitor = { path = "../event_monitor" }
io-uring = "0.5.2"
libc = "0.2.101"
libc = "0.2.103"
log = "0.4.14"
net_gen = { path = "../net_gen" }
net_util = { path = "../net_util" }
pci = { path = "../pci" }
rate_limiter = { path = "../rate_limiter" }
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
seccompiler = "0.2.0"
serde = "1.0.130"
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vhost = { version = "0.1.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
vhost = { version = "0.2.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -29,12 +29,15 @@ use std::result;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::mpsc;
use std::sync::{Arc, Barrier, Mutex};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_memory::GuestMemory;
use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
GuestMemoryError,
};
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
use vm_migration::VersionMapped;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 128;
@@ -82,8 +85,8 @@ pub enum Error {
// Got from include/uapi/linux/virtio_balloon.h
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
struct VirtioBalloonConfig {
#[derive(Copy, Clone, Debug, Default, Versionize)]
pub struct VirtioBalloonConfig {
// Number of pages host wants Guest to give up.
num_pages: u32,
// Number of pages we've actually got in balloon.
@@ -120,11 +123,11 @@ struct VirtioBalloonResize {
}
impl VirtioBalloonResize {
pub fn new() -> io::Result<Self> {
pub fn new(size: u64) -> io::Result<Self> {
let (tx, rx) = mpsc::channel();
Ok(Self {
size: Arc::new(AtomicU64::new(0)),
size: Arc::new(AtomicU64::new(size)),
tx,
rx,
evt: EventFd::new(EFD_NONBLOCK)?,
@@ -335,6 +338,15 @@ impl EpollHelperHandler for BalloonEpollHandler {
}
}
#[derive(Versionize)]
pub struct BalloonState {
pub avail_features: u64,
pub acked_features: u64,
pub config: VirtioBalloonConfig,
}
impl VersionMapped for BalloonState {}
// Virtio device for exposing entropy to the guest OS through virtio.
pub struct Balloon {
common: VirtioCommon,
@@ -374,7 +386,7 @@ impl Balloon {
..Default::default()
},
id,
resize: VirtioBalloonResize::new()?,
resize: VirtioBalloonResize::new(size)?,
config: Arc::new(Mutex::new(config)),
seccomp_action,
exit_evt,
@@ -389,6 +401,20 @@ impl Balloon {
pub fn get_actual(&self) -> u64 {
(self.config.lock().unwrap().actual as u64) << VIRTIO_BALLOON_PFN_SHIFT
}
fn state(&self) -> BalloonState {
BalloonState {
avail_features: self.common.avail_features,
acked_features: self.common.acked_features,
config: *(self.config.lock().unwrap()),
}
}
fn set_state(&mut self, state: &BalloonState) {
self.common.avail_features = state.avail_features;
self.common.acked_features = state.acked_features;
*(self.config.lock().unwrap()) = state.config;
}
}
impl Drop for Balloon {
@@ -503,6 +529,15 @@ impl Snapshottable for Balloon {
fn id(&self) -> String {
self.id.clone()
}
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(())
}
}
impl Transportable for Balloon {}
impl Migratable for Balloon {}

View File

@@ -11,7 +11,7 @@ use crate::seccomp_filters::Thread;
use crate::thread_helper::spawn_virtio_thread;
use crate::GuestMemoryMmap;
use crate::VirtioInterrupt;
use libc::EFD_NONBLOCK;
use libc::{EFD_NONBLOCK, TIOCGWINSZ};
use seccompiler::SeccompAction;
use std::cmp;
use std::collections::VecDeque;
@@ -42,11 +42,13 @@ const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
// File written to (input ready)
const FILE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 5;
// Console resized
const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 6;
//Console size feature bit
const VIRTIO_CONSOLE_F_SIZE: u64 = 0;
#[derive(Copy, Clone, Debug, Default, Versionize)]
#[derive(Copy, Clone, Debug, Versionize)]
#[repr(C, packed)]
pub struct VirtioConsoleConfig {
cols: u16,
@@ -55,6 +57,17 @@ pub struct VirtioConsoleConfig {
emerg_wr: u32,
}
impl Default for VirtioConsoleConfig {
fn default() -> Self {
VirtioConsoleConfig {
cols: 0,
rows: 0,
max_nr_ports: 1,
emerg_wr: 0,
}
}
}
// Safe because it only has data and has no implicit padding.
unsafe impl ByteValued for VirtioConsoleConfig {}
@@ -63,11 +76,13 @@ struct ConsoleEpollHandler {
mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>,
in_buffer: Arc<Mutex<VecDeque<u8>>>,
resizer: Arc<ConsoleResizer>,
endpoint: Endpoint,
input_queue_evt: EventFd,
output_queue_evt: EventFd,
input_evt: EventFd,
config_evt: EventFd,
resize_pipe: Option<File>,
kill_evt: EventFd,
pause_evt: EventFd,
}
@@ -199,6 +214,9 @@ impl ConsoleEpollHandler {
helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?;
helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?;
helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?;
if let Some(resize_pipe) = self.resize_pipe.as_ref() {
helper.add_event(resize_pipe.as_raw_fd(), RESIZE_EVENT)?;
}
if let Some(in_file) = self.endpoint.in_file() {
helper.add_event(in_file.as_raw_fd(), FILE_EVENT)?;
}
@@ -254,6 +272,14 @@ impl EpollHelperHandler for ConsoleEpollHandler {
return true;
}
}
RESIZE_EVENT => {
if let Err(e) = self.resize_pipe.as_ref().unwrap().read_exact(&mut [0]) {
error!("Failed to get resize event: {:?}", e);
return true;
}
self.resizer.update_console_size();
}
FILE_EVENT => {
let mut input = [0u8; 64];
if let Some(ref mut in_file) = self.endpoint.in_file() {
@@ -282,34 +308,29 @@ impl EpollHelperHandler for ConsoleEpollHandler {
/// Resize handler
pub struct ConsoleResizer {
config_evt: EventFd,
tty: Option<File>,
config: Arc<Mutex<VirtioConsoleConfig>>,
acked_features: AtomicU64,
}
impl ConsoleResizer {
pub fn update_console_size(&self, cols: u16, rows: u16) {
if self
.acked_features
.fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel)
!= 0
{
pub fn update_console_size(&self) {
if let Some(tty) = self.tty.as_ref() {
let (cols, rows) = get_win_size(tty);
self.config.lock().unwrap().update_console_size(cols, rows);
//Send the interrupt to the driver
let _ = self.config_evt.write(1);
if self
.acked_features
.fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel)
!= 0
{
// Send the interrupt to the driver
let _ = self.config_evt.write(1);
}
}
}
}
impl VirtioConsoleConfig {
pub fn new(cols: u16, rows: u16) -> Self {
VirtioConsoleConfig {
cols,
rows,
max_nr_ports: 1u32,
emerg_wr: 0u32,
}
}
pub fn update_console_size(&mut self, cols: u16, rows: u16) {
self.cols = cols;
self.rows = rows;
@@ -322,6 +343,7 @@ pub struct Console {
id: String,
config: Arc<Mutex<VirtioConsoleConfig>>,
resizer: Arc<ConsoleResizer>,
resize_pipe: Option<File>,
endpoint: Endpoint,
seccomp_action: SeccompAction,
in_buffer: Arc<Mutex<VecDeque<u8>>>,
@@ -336,6 +358,24 @@ pub struct ConsoleState {
in_buffer: Vec<u8>,
}
fn get_win_size(tty: &dyn AsRawFd) -> (u16, u16) {
#[repr(C)]
#[derive(Default)]
struct WindowSize {
rows: u16,
cols: u16,
xpixel: u16,
ypixel: u16,
}
let ws: WindowSize = WindowSize::default();
unsafe {
libc::ioctl(tty.as_raw_fd(), TIOCGWINSZ, &ws);
}
(ws.cols, ws.rows)
}
impl VersionMapped for ConsoleState {}
impl Console {
@@ -343,8 +383,7 @@ impl Console {
pub fn new(
id: String,
endpoint: Endpoint,
cols: u16,
rows: u16,
resize_pipe: Option<File>,
iommu: bool,
seccomp_action: SeccompAction,
exit_evt: EventFd,
@@ -356,13 +395,16 @@ impl Console {
}
let config_evt = EventFd::new(EFD_NONBLOCK).unwrap();
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows)));
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::default()));
let resizer = Arc::new(ConsoleResizer {
config_evt,
config: console_config.clone(),
tty: endpoint.out_file().as_ref().map(|t| t.try_clone().unwrap()),
acked_features: AtomicU64::new(0),
});
resizer.update_console_size();
Ok((
Console {
common: VirtioCommon {
@@ -376,6 +418,7 @@ impl Console {
id,
config: console_config,
resizer: resizer.clone(),
resize_pipe,
endpoint,
seccomp_action,
in_buffer: Arc::new(Mutex::new(VecDeque::new())),
@@ -463,6 +506,8 @@ impl VirtioDevice for Console {
output_queue_evt: queue_evts.remove(0),
input_evt,
config_evt: self.resizer.config_evt.try_clone().unwrap(),
resize_pipe: self.resize_pipe.as_ref().map(|p| p.try_clone().unwrap()),
resizer: Arc::clone(&self.resizer),
kill_evt,
pause_evt,
};

View File

@@ -54,8 +54,6 @@ const EVENT_Q_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
/// will conflict with x86.
const PROBE_PROP_SIZE: u32 =
(size_of::<VirtioIommuProbeProperty>() + size_of::<VirtioIommuProbeResvMem>()) as u32;
const MSI_IOVA_START: u64 = 0xfee0_0000;
const MSI_IOVA_END: u64 = 0xfeef_ffff;
/// Virtio IOMMU features
#[allow(unused)]
@@ -352,6 +350,7 @@ impl Request {
mapping: &Arc<IommuMapping>,
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
ext_domain_mapping: &mut BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
msi_iova_space: (u64, u64),
) -> result::Result<usize, Error> {
// The head contains the request type which MUST be readable.
if avail_desc.is_write_only() {
@@ -372,6 +371,8 @@ impl Request {
return Err(Error::InvalidRequest);
};
let (msi_iova_start, msi_iova_end) = msi_iova_space;
// Create the reply
let mut reply: Vec<u8> = Vec::new();
@@ -515,8 +516,8 @@ impl Request {
let resv_mem = VirtioIommuProbeResvMem {
subtype: VIRTIO_IOMMU_RESV_MEM_T_MSI,
start: MSI_IOVA_START,
end: MSI_IOVA_END,
start: msi_iova_start,
end: msi_iova_end,
..Default::default()
};
reply.extend_from_slice(resv_mem.as_slice());
@@ -562,6 +563,7 @@ struct IommuEpollHandler {
mapping: Arc<IommuMapping>,
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
ext_domain_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
msi_iova_space: (u64, u64),
}
impl IommuEpollHandler {
@@ -576,6 +578,7 @@ impl IommuEpollHandler {
&self.mapping,
&self.ext_mapping,
&mut self.ext_domain_mapping,
self.msi_iova_space,
) {
Ok(len) => len as u32,
Err(e) => {
@@ -702,6 +705,7 @@ pub struct Iommu {
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
seccomp_action: SeccompAction,
exit_evt: EventFd,
msi_iova_space: (u64, u64),
}
#[derive(Versionize)]
@@ -719,6 +723,7 @@ impl Iommu {
id: String,
seccomp_action: SeccompAction,
exit_evt: EventFd,
msi_iova_space: (u64, u64),
) -> io::Result<(Self, Arc<IommuMapping>)> {
let config = VirtioIommuConfig {
page_size_mask: VIRTIO_IOMMU_PAGE_SIZE_MASK,
@@ -748,6 +753,7 @@ impl Iommu {
ext_mapping: BTreeMap::new(),
seccomp_action,
exit_evt,
msi_iova_space,
},
mapping,
))
@@ -843,6 +849,7 @@ impl VirtioDevice for Iommu {
mapping: self.mapping.clone(),
ext_mapping: self.ext_mapping.clone(),
ext_domain_mapping: BTreeMap::new(),
msi_iova_space: self.msi_iova_space,
};
let paused = self.common.paused.clone();

View File

@@ -33,12 +33,17 @@ use std::result;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::mpsc;
use std::sync::{Arc, Barrier, Mutex};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
GuestMemoryError, GuestMemoryRegion,
};
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
use vm_migration::protocol::MemoryRangeTable;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: u16 = 128;
@@ -159,8 +164,8 @@ struct VirtioMemResp {
unsafe impl ByteValued for VirtioMemResp {}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
struct VirtioMemConfig {
#[derive(Copy, Clone, Debug, Default, Versionize)]
pub struct VirtioMemConfig {
// Block size and alignment. Cannot change.
block_size: u64,
// Valid with VIRTIO_MEM_F_ACPI_PXM. Cannot change.
@@ -320,14 +325,14 @@ impl Request {
}
pub struct ResizeSender {
size: Arc<AtomicU64>,
hotplugged_size: Arc<AtomicU64>,
tx: mpsc::Sender<Result<(), Error>>,
evt: EventFd,
}
impl ResizeSender {
fn size(&self) -> u64 {
self.size.load(Ordering::Acquire)
self.hotplugged_size.load(Ordering::Acquire)
}
fn send(&self, r: Result<(), Error>) -> Result<(), mpsc::SendError<Result<(), Error>>> {
@@ -338,7 +343,7 @@ impl ResizeSender {
impl Clone for ResizeSender {
fn clone(&self) -> Self {
ResizeSender {
size: self.size.clone(),
hotplugged_size: self.hotplugged_size.clone(),
tx: self.tx.clone(),
evt: self
.evt
@@ -349,18 +354,18 @@ impl Clone for ResizeSender {
}
pub struct Resize {
size: Arc<AtomicU64>,
hotplugged_size: Arc<AtomicU64>,
tx: mpsc::Sender<Result<(), Error>>,
rx: mpsc::Receiver<Result<(), Error>>,
evt: EventFd,
}
impl Resize {
pub fn new() -> io::Result<Self> {
pub fn new(hotplugged_size: u64) -> io::Result<Self> {
let (tx, rx) = mpsc::channel();
Ok(Resize {
size: Arc::new(AtomicU64::new(0)),
hotplugged_size: Arc::new(AtomicU64::new(hotplugged_size)),
tx,
rx,
evt: EventFd::new(EFD_NONBLOCK)?,
@@ -369,25 +374,34 @@ impl Resize {
pub fn new_resize_sender(&self) -> Result<ResizeSender, Error> {
Ok(ResizeSender {
size: self.size.clone(),
hotplugged_size: self.hotplugged_size.clone(),
tx: self.tx.clone(),
evt: self.evt.try_clone().map_err(Error::EventFdTryCloneFail)?,
})
}
pub fn work(&self, size: u64) -> Result<(), Error> {
self.size.store(size, Ordering::Release);
pub fn work(&self, desired_size: u64) -> Result<(), Error> {
self.hotplugged_size.store(desired_size, Ordering::Release);
self.evt.write(1).map_err(Error::EventFdWriteFail)?;
self.rx.recv().map_err(Error::MpscRecvFail)?
}
}
struct BlocksState(Vec<bool>);
#[derive(Clone, Versionize)]
pub struct BlocksState {
bitmap: Vec<bool>,
}
impl BlocksState {
pub fn new(region_size: u64) -> Self {
BlocksState {
bitmap: vec![false; (region_size / VIRTIO_MEM_DEFAULT_BLOCK_SIZE) as usize],
}
}
fn is_range_state(&self, first_block_index: usize, nb_blocks: u16, plug: bool) -> bool {
for state in self
.0
.bitmap
.iter()
.skip(first_block_index)
.take(nb_blocks as usize)
@@ -401,7 +415,7 @@ impl BlocksState {
fn set_range(&mut self, first_block_index: usize, nb_blocks: u16, plug: bool) {
for state in self
.0
.bitmap
.iter_mut()
.skip(first_block_index)
.take(nb_blocks as usize)
@@ -411,7 +425,27 @@ impl BlocksState {
}
fn inner(&self) -> &Vec<bool> {
&self.0
&self.bitmap
}
pub fn memory_ranges(&self, start_addr: u64, plugged: bool) -> MemoryRangeTable {
let mut bitmap: Vec<u64> = Vec::new();
let mut i = 0;
for (j, bit) in self.bitmap.iter().enumerate() {
if j % 64 == 0 {
bitmap.push(0);
if j != 0 {
i += 1;
}
}
if *bit == plugged {
bitmap[i] |= 1 << (j % 64);
}
}
MemoryRangeTable::from_bitmap(bitmap, start_addr, VIRTIO_MEM_DEFAULT_BLOCK_SIZE)
}
}
@@ -428,7 +462,7 @@ struct MemEpollHandler {
kill_evt: EventFd,
pause_evt: EventFd,
hugepages: bool,
dma_mapping_handlers: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
dma_mapping_handlers: Arc<Mutex<BTreeMap<VirtioMemMappingSource, Arc<dyn ExternalDmaMapping>>>>,
}
impl MemEpollHandler {
@@ -734,7 +768,22 @@ impl EpollHelperHandler for MemEpollHandler {
}
}
// Virtio device for exposing entropy to the guest OS through virtio.
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum VirtioMemMappingSource {
Container,
Device(u32),
}
#[derive(Versionize)]
pub struct MemState {
pub avail_features: u64,
pub acked_features: u64,
pub config: VirtioMemConfig,
pub blocks_state: BlocksState,
}
impl VersionMapped for MemState {}
pub struct Mem {
common: VirtioCommon,
id: String,
@@ -744,7 +793,7 @@ pub struct Mem {
config: Arc<Mutex<VirtioMemConfig>>,
seccomp_action: SeccompAction,
hugepages: bool,
dma_mapping_handlers: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
dma_mapping_handlers: Arc<Mutex<BTreeMap<VirtioMemMappingSource, Arc<dyn ExternalDmaMapping>>>>,
blocks_state: Arc<Mutex<BlocksState>>,
exit_evt: EventFd,
}
@@ -761,6 +810,7 @@ impl Mem {
initial_size: u64,
hugepages: bool,
exit_evt: EventFd,
blocks_state: Arc<Mutex<BlocksState>>,
) -> io::Result<Mem> {
let region_len = region.len();
@@ -833,18 +883,14 @@ impl Mem {
seccomp_action,
hugepages,
dma_mapping_handlers: Arc::new(Mutex::new(BTreeMap::new())),
blocks_state: Arc::new(Mutex::new(BlocksState(vec![
false;
(config.region_size / config.block_size)
as usize
]))),
blocks_state,
exit_evt,
})
}
pub fn add_dma_mapping_handler(
&mut self,
device_id: u32,
source: VirtioMemMappingSource,
handler: Arc<dyn ExternalDmaMapping>,
) -> result::Result<(), Error> {
let config = self.config.lock().unwrap();
@@ -863,17 +909,20 @@ impl Mem {
self.dma_mapping_handlers
.lock()
.unwrap()
.insert(device_id, handler);
.insert(source, handler);
Ok(())
}
pub fn remove_dma_mapping_handler(&mut self, device_id: u32) -> result::Result<(), Error> {
pub fn remove_dma_mapping_handler(
&mut self,
source: VirtioMemMappingSource,
) -> result::Result<(), Error> {
let handler = self
.dma_mapping_handlers
.lock()
.unwrap()
.remove(&device_id)
.remove(&source)
.ok_or(Error::InvalidDmaMappingHandler)?;
let config = self.config.lock().unwrap();
@@ -891,6 +940,22 @@ impl Mem {
Ok(())
}
fn state(&self) -> MemState {
MemState {
avail_features: self.common.avail_features,
acked_features: self.common.acked_features,
config: *(self.config.lock().unwrap()),
blocks_state: self.blocks_state.lock().unwrap().clone(),
}
}
fn set_state(&mut self, state: &MemState) {
self.common.avail_features = state.avail_features;
self.common.acked_features = state.acked_features;
*(self.config.lock().unwrap()) = state.config;
*(self.blocks_state.lock().unwrap()) = state.blocks_state.clone();
}
}
impl Drop for Mem {
@@ -932,7 +997,6 @@ impl VirtioDevice for Mem {
) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds();
let config = self.config.lock().unwrap();
let mut handler = MemEpollHandler {
host_addr: self.host_addr,
host_fd: self.host_fd,
@@ -949,12 +1013,20 @@ impl VirtioDevice for Mem {
dma_mapping_handlers: Arc::clone(&self.dma_mapping_handlers),
};
handler
.discard_memory_range(0, config.region_size)
.map_err(|e| {
error!("failed discarding memory range: {:?}", e);
ActivateError::BadActivate
})?;
let unplugged_memory_ranges = self.blocks_state.lock().unwrap().memory_ranges(0, false);
for range in unplugged_memory_ranges.regions() {
handler
.discard_memory_range(range.gpa, range.length)
.map_err(|e| {
error!(
"failed discarding memory range [0x{:x}-0x{:x}]: {:?}",
range.gpa,
range.gpa + range.length - 1,
e
);
ActivateError::BadActivate
})?;
}
let paused = self.common.paused.clone();
let paused_sync = self.common.paused_sync.clone();
@@ -999,6 +1071,15 @@ impl Snapshottable for Mem {
fn id(&self) -> String {
self.id.clone()
}
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(())
}
}
impl Transportable for Mem {}
impl Migratable for Mem {}

View File

@@ -48,6 +48,7 @@ macro_rules! or {
}
// See include/uapi/asm-generic/ioctls.h in the kernel code.
const TIOCGWINSZ: u64 = 0x5413;
const FIONBIO: u64 = 0x5421;
// See include/uapi/linux/vfio.h in the kernel code.
@@ -57,6 +58,10 @@ const VFIO_IOMMU_UNMAP_DMA: u64 = 0x3b72;
// See include/uapi/linux/if_tun.h in the kernel code.
const TUNSETOFFLOAD: u64 = 0x4004_54d0;
fn create_virtio_console_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ).unwrap()]]
}
fn create_virtio_iommu_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA).unwrap()],
@@ -72,171 +77,62 @@ fn create_virtio_mem_ioctl_seccomp_rule() -> Vec<SeccompRule> {
}
fn virtio_balloon_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_fallocate, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
vec![(libc::SYS_fallocate, vec![])]
}
fn virtio_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_fallocate, vec![]),
(libc::SYS_fdatasync, vec![]),
(libc::SYS_fsync, vec![]),
(libc::SYS_ftruncate, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_getrandom, vec![]),
(libc::SYS_io_uring_enter, vec![]),
(libc::SYS_lseek, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_pread64, vec![]),
(libc::SYS_preadv, vec![]),
(libc::SYS_pwritev, vec![]),
(libc::SYS_pwrite64, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_timerfd_settime, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_console_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_ioctl, create_virtio_console_ioctl_seccomp_rule()),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_iommu_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_ioctl, create_virtio_iommu_ioctl_seccomp_rule()),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_fallocate, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
(libc::SYS_madvise, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_sendmsg, vec![]),
]
}
fn virtio_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_readv, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_timerfd_settime, vec![]),
(libc::SYS_write, vec![]),
(libc::SYS_writev, vec![]),
]
}
@@ -246,191 +142,57 @@ fn create_virtio_net_ctl_ioctl_seccomp_rule() -> Vec<SeccompRule> {
}
fn virtio_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_ioctl, create_virtio_net_ctl_ioctl_seccomp_rule()),
(libc::SYS_madvise, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
vec![(libc::SYS_ioctl, create_virtio_net_ctl_ioctl_seccomp_rule())]
}
fn virtio_pmem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_fsync, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
vec![(libc::SYS_fsync, vec![])]
}
fn virtio_rng_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_connect, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_nanosleep, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_socket, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
vec![]
}
fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_accept4, vec![]),
(libc::SYS_bind, vec![]),
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_getcwd, vec![]),
(libc::SYS_listen, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_socket, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_unlink, vec![]),
#[cfg(target_arch = "aarch64")]
(libc::SYS_unlinkat, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_vhost_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
vec![]
}
fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
@@ -440,63 +202,25 @@ fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
fn virtio_vsock_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_accept4, vec![]),
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_connect, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_ioctl, create_vsock_ioctl_seccomp_rule()),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_socket, vec![]),
(libc::SYS_write, vec![]),
]
}
fn virtio_watchdog_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_timerfd_settime, vec![]),
(libc::SYS_write, vec![]),
]
}
fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
match thread_type {
let mut rules = match thread_type {
Thread::VirtioBalloon => virtio_balloon_thread_rules(),
Thread::VirtioBlock => virtio_block_thread_rules(),
Thread::VirtioConsole => virtio_console_thread_rules(),
@@ -512,7 +236,33 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(),
Thread::VirtioVsock => virtio_vsock_thread_rules(),
Thread::VirtioWatchdog => virtio_watchdog_thread_rules(),
}
};
rules.append(&mut virtio_thread_common());
rules
}
fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
(libc::SYS_epoll_ctl, vec![]),
(libc::SYS_epoll_pwait, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_epoll_wait, vec![]),
(libc::SYS_exit, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
}
/// Generate a BPF program based on the seccomp_action value

View File

@@ -521,7 +521,14 @@ impl VirtioDevice for Fs {
MasterReqHandler::new(vu_master_req_handler).map_err(|e| {
ActivateError::VhostUserFsSetup(Error::MasterReqHandlerCreation(e))
})?;
req_handler.set_reply_ack_flag(true);
if self.vu_common.acked_protocol_features
& VhostUserProtocolFeatures::REPLY_ACK.bits()
!= 0
{
req_handler.set_reply_ack_flag(true);
}
Some(req_handler)
} else {
None

View File

@@ -554,7 +554,7 @@ impl VhostUserHandle {
let ptr = region.as_ptr() as *const u64;
std::slice::from_raw_parts(ptr, len).to_vec()
};
Ok(MemoryRangeTable::from_bitmap(bitmap, 0))
Ok(MemoryRangeTable::from_bitmap(bitmap, 0, 4096))
} else {
Err(Error::MissingShmLogRegion)
}

View File

@@ -5,6 +5,6 @@ authors = ["The Chromium OS Authors"]
edition = "2018"
[dependencies]
libc = "0.2.101"
libc = "0.2.103"
vm-memory = "0.6.0"
arch = { path = "../arch" }

View File

@@ -10,12 +10,12 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.43"
thiserror = "1.0.29"
anyhow = "1.0.44"
thiserror = "1.0.30"
serde = { version = "1.0.130", features = ["rc"] }
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
vm-memory = { version = "0.6.0", features = ["backend-mmap"] }
vmm-sys-util = "0.8.0"
vmm-sys-util = "0.9.0"

View File

@@ -5,11 +5,11 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
[dependencies]
anyhow = "1.0.43"
thiserror = "1.0.29"
anyhow = "1.0.44"
thiserror = "1.0.30"
serde = { version = "1.0.130", features = ["rc"] }
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }

View File

@@ -15,7 +15,7 @@ use versionize::{VersionMap, Versionize};
pub mod protocol;
/// Global VMM version for versioning
const MAJOR_VERSION: u16 = 18;
const MAJOR_VERSION: u16 = 19;
const MINOR_VERSION: u16 = 0;
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;

View File

@@ -3,7 +3,10 @@
// SPDX-License-Identifier: Apache-2.0
//
use crate::MigratableError;
use crate::{MigratableError, VersionMapped};
use std::io::{Read, Write};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_memory::ByteValued;
// Migration protocol
@@ -28,8 +31,6 @@ use vm_memory::ByteValued;
// The destination can at any time send an "error response" to cancel
// The source can at any time send an "abandon request" to cancel
use std::io::{Read, Write};
#[repr(u16)]
#[derive(Copy, Clone)]
pub enum Command {
@@ -173,19 +174,21 @@ impl Response {
unsafe impl ByteValued for Response {}
#[repr(C)]
#[derive(Clone, Serialize, Deserialize, Versionize)]
pub struct MemoryRange {
pub gpa: u64,
pub length: u64,
}
#[derive(Default)]
#[derive(Clone, Default, Serialize, Deserialize, Versionize)]
pub struct MemoryRangeTable {
data: Vec<MemoryRange>,
}
impl VersionMapped for MemoryRangeTable {}
impl MemoryRangeTable {
pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64) -> Self {
let page_size = 4096;
pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64, page_size: u64) -> Self {
let mut table = MemoryRangeTable::default();
let mut entry: Option<MemoryRange> = None;
for (i, block) in bitmap.iter().enumerate() {

View File

@@ -16,8 +16,8 @@ tdx = ["arch/tdx", "hypervisor/tdx"]
[dependencies]
acpi_tables = { path = "../acpi_tables", optional = true }
anyhow = "1.0.43"
arc-swap = "1.3.2"
anyhow = "1.0.44"
arc-swap = "1.4.0"
arch = { path = "../arch" }
bitflags = "1.3.2"
block_util = { path = "../block_util" }
@@ -27,24 +27,25 @@ epoll = "4.3.1"
event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" }
lazy_static = "1.4.0"
libc = "0.2.101"
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
libc = "0.2.103"
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
log = "0.4.14"
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" }
pci = { path = "../pci" }
qcow = { path = "../qcow" }
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
seccompiler = "0.2.0"
serde = { version = "1.0.130", features = ["rc"] }
serde_derive = "1.0.130"
serde_json = "1.0.67"
serde_json = "1.0.68"
signal-hook = "0.3.10"
thiserror = "1.0.29"
thiserror = "1.0.30"
uuid = "0.8.2"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
vfio_user = { path = "../vfio_user" }
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
vm-allocator = { path = "../vm-allocator" }
@@ -52,7 +53,7 @@ vm-device = { path = "../vm-device" }
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
[dev-dependencies]
credibility = "0.1.3"

View File

@@ -233,7 +233,7 @@ fn create_mcfg_table() -> Sdt {
base_address: arch::layout::PCI_MMCONFIG_START.0,
segment: 0,
start: 0,
end: ((arch::layout::PCI_MMCONFIG_SIZE - 1) >> 20) as u8,
end: 0,
..Default::default()
});
mcfg

View File

@@ -14,6 +14,7 @@ use std::collections::HashMap;
use std::fs::File;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixListener;
use std::panic::AssertUnwindSafe;
use std::path::PathBuf;
use std::sync::mpsc::Sender;
use std::sync::Arc;
@@ -267,6 +268,7 @@ fn start_http_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
// Retrieve seccomp filter for API thread
let api_seccomp_filter =
@@ -277,32 +279,44 @@ fn start_http_thread(
.spawn(move || {
// Apply seccomp filter for API thread.
if !api_seccomp_filter.is_empty() {
apply_filter(&api_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
apply_filter(&api_seccomp_filter)
.map_err(Error::ApplySeccompFilter)
.map_err(|e| {
error!("Error applying seccomp filter: {:?}", e);
exit_evt.write(1).ok();
e
})?;
}
server.start_server().unwrap();
loop {
match server.requests() {
Ok(request_vec) => {
for server_request in request_vec {
server
.respond(server_request.process(|request| {
std::panic::catch_unwind(AssertUnwindSafe(move || {
server.start_server().unwrap();
loop {
match server.requests() {
Ok(request_vec) => {
for server_request in request_vec {
if let Err(e) = server.respond(server_request.process(|request| {
handle_http_request(request, &api_notifier, &api_sender)
}))
.or_else(|e| {
})) {
error!("HTTP server error on response: {}", e);
Ok(())
})?;
}
}
}
Err(e) => {
error!(
"HTTP server error on retrieving incoming request. Error: {}",
e
);
}
}
Err(e) => {
error!(
"HTTP server error on retrieving incoming request. Error: {}",
e
);
}
}
}
}))
.map_err(|_| {
error!("http-server thread panicked");
exit_evt.write(1).ok()
})
.ok();
Ok(())
})
.map_err(Error::HttpThreadSpawn)
}
@@ -312,13 +326,14 @@ pub fn start_http_path_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
std::fs::remove_file(path).unwrap_or_default();
let socket_path = PathBuf::from(path);
let socket_fd = UnixListener::bind(socket_path).map_err(Error::CreateApiServerSocket)?;
let server =
HttpServer::new_from_fd(socket_fd.into_raw_fd()).map_err(Error::CreateApiServer)?;
start_http_thread(server, api_notifier, api_sender, seccomp_action)
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
}
pub fn start_http_fd_thread(
@@ -326,7 +341,8 @@ pub fn start_http_fd_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
let server = HttpServer::new_from_fd(fd).map_err(Error::CreateApiServer)?;
start_http_thread(server, api_notifier, api_sender, seccomp_action)
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
}

View File

@@ -546,6 +546,9 @@ components:
hotplugged_size:
type: integer
format: int64
prefault:
type: boolean
default: false
MemoryConfig:
required:
@@ -577,6 +580,9 @@ components:
hugepage_size:
type: integer
format: int64
prefault:
type: boolean
default: false
zones:
type: array
items:

27
vmm/src/clone3.rs Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2021 Alyssa Ross <hi@alyssa.is>
// SPDX-License-Identifier: Apache-2.0
use libc::{c_long, size_t, syscall, SYS_clone3};
pub const CLONE_CLEAR_SIGHAND: u64 = 0x100000000;
#[repr(C)]
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct clone_args {
pub flags: u64,
pub pidfd: u64,
pub child_tid: u64,
pub parent_tid: u64,
pub exit_signal: u64,
pub stack: u64,
pub stack_size: u64,
pub tls: u64,
pub set_tid: u64,
pub set_tid_size: u64,
pub cgroup: u64,
}
pub unsafe fn clone3(args: &mut clone_args, size: size_t) -> c_long {
syscall(SYS_clone3, args, size)
}

View File

@@ -20,6 +20,12 @@ use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
pub const DEFAULT_VCPUS: u8 = 1;
pub const DEFAULT_MEMORY_MB: u64 = 512;
// When booting with PVH boot the maximum physical addressable size
// is a 46 bit address space even when the host supports with 5-level
// paging.
pub const DEFAULT_MAX_PHYS_BITS: u8 = 46;
pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
pub const DEFAULT_NUM_QUEUES_VUNET: usize = 2;
pub const DEFAULT_QUEUE_SIZE_VUNET: u16 = 256;
@@ -410,6 +416,10 @@ impl FromStr for CpuTopology {
}
}
fn default_cpuconfig_max_phys_bits() -> u8 {
DEFAULT_MAX_PHYS_BITS
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct CpusConfig {
pub boot_vcpus: u8,
@@ -418,8 +428,8 @@ pub struct CpusConfig {
pub topology: Option<CpuTopology>,
#[serde(default)]
pub kvm_hyperv: bool,
#[serde(default)]
pub max_phys_bits: Option<u8>,
#[serde(default = "default_cpuconfig_max_phys_bits")]
pub max_phys_bits: u8,
}
impl CpusConfig {
@@ -449,7 +459,8 @@ impl CpusConfig {
.0;
let max_phys_bits = parser
.convert::<u8>("max_phys_bits")
.map_err(Error::ParseCpus)?;
.map_err(Error::ParseCpus)?
.unwrap_or(DEFAULT_MAX_PHYS_BITS);
Ok(CpusConfig {
boot_vcpus,
@@ -468,7 +479,7 @@ impl Default for CpusConfig {
max_vcpus: DEFAULT_VCPUS,
topology: None,
kvm_hyperv: false,
max_phys_bits: None,
max_phys_bits: DEFAULT_MAX_PHYS_BITS,
}
}
}
@@ -491,6 +502,8 @@ pub struct MemoryZoneConfig {
pub hotplug_size: Option<u64>,
#[serde(default)]
pub hotplugged_size: Option<u64>,
#[serde(default)]
pub prefault: bool,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
@@ -511,6 +524,8 @@ pub struct MemoryConfig {
#[serde(default)]
pub hugepage_size: Option<u64>,
#[serde(default)]
pub prefault: bool,
#[serde(default)]
pub zones: Option<Vec<MemoryZoneConfig>>,
}
@@ -526,7 +541,8 @@ impl MemoryConfig {
.add("hotplugged_size")
.add("shared")
.add("hugepages")
.add("hugepage_size");
.add("hugepage_size")
.add("prefault");
parser.parse(memory).map_err(Error::ParseMemory)?;
let size = parser
@@ -565,6 +581,11 @@ impl MemoryConfig {
.convert::<ByteSized>("hugepage_size")
.map_err(Error::ParseMemory)?
.map(|v| v.0);
let prefault = parser
.convert::<Toggle>("prefault")
.map_err(Error::ParseMemory)?
.unwrap_or(Toggle(false))
.0;
let zones: Option<Vec<MemoryZoneConfig>> = if let Some(memory_zones) = &memory_zones {
let mut zones = Vec::new();
@@ -579,7 +600,8 @@ impl MemoryConfig {
.add("hugepage_size")
.add("host_numa_node")
.add("hotplug_size")
.add("hotplugged_size");
.add("hotplugged_size")
.add("prefault");
parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?;
let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?;
@@ -615,6 +637,11 @@ impl MemoryConfig {
.convert::<ByteSized>("hotplugged_size")
.map_err(Error::ParseMemoryZone)?
.map(|v| v.0);
let prefault = parser
.convert::<Toggle>("prefault")
.map_err(Error::ParseMemoryZone)?
.unwrap_or(Toggle(false))
.0;
zones.push(MemoryZoneConfig {
id,
@@ -626,6 +653,7 @@ impl MemoryConfig {
host_numa_node,
hotplug_size,
hotplugged_size,
prefault,
});
}
Some(zones)
@@ -642,6 +670,7 @@ impl MemoryConfig {
shared,
hugepages,
hugepage_size,
prefault,
zones,
})
}
@@ -676,6 +705,7 @@ impl Default for MemoryConfig {
shared: false,
hugepages: false,
hugepage_size: None,
prefault: false,
zones: None,
}
}
@@ -2678,6 +2708,7 @@ mod tests {
shared: false,
hugepages: false,
hugepage_size: None,
prefault: false,
zones: None,
},
kernel: Some(KernelConfig {

View File

@@ -406,14 +406,14 @@ const CPU_SELECTION_OFFSET: u64 = 0;
impl BusDevice for CpuManager {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
// The Linux kernel, quite reasonably, doesn't zero the memory it gives us.
data.copy_from_slice(&[0; 8][0..data.len()]);
data.fill(0);
match offset {
CPU_SELECTION_OFFSET => {
data[0] = self.selected_cpu;
}
CPU_STATUS_OFFSET => {
if self.selected_cpu < self.present_vcpus() {
if self.selected_cpu < self.max_vcpus() {
let state = &self.vcpu_states[usize::from(self.selected_cpu)];
if state.active() {
data[0] |= 1 << CPU_ENABLE_FLAG;
@@ -424,6 +424,8 @@ impl BusDevice for CpuManager {
if state.removing {
data[0] |= 1 << CPU_REMOVING_FLAG;
}
} else {
warn!("Out of range vCPU id: {}", self.selected_cpu);
}
}
_ => {
@@ -441,23 +443,28 @@ impl BusDevice for CpuManager {
self.selected_cpu = data[0];
}
CPU_STATUS_OFFSET => {
let state = &mut self.vcpu_states[usize::from(self.selected_cpu)];
// The ACPI code writes back a 1 to acknowledge the insertion
if (data[0] & (1 << CPU_INSERTING_FLAG) == 1 << CPU_INSERTING_FLAG)
&& state.inserting
{
state.inserting = false;
}
// Ditto for removal
if (data[0] & (1 << CPU_REMOVING_FLAG) == 1 << CPU_REMOVING_FLAG) && state.removing
{
state.removing = false;
}
// Trigger removal of vCPU
if data[0] & (1 << CPU_EJECT_FLAG) == 1 << CPU_EJECT_FLAG {
if let Err(e) = self.remove_vcpu(self.selected_cpu) {
error!("Error removing vCPU: {:?}", e);
if self.selected_cpu < self.max_vcpus() {
let state = &mut self.vcpu_states[usize::from(self.selected_cpu)];
// The ACPI code writes back a 1 to acknowledge the insertion
if (data[0] & (1 << CPU_INSERTING_FLAG) == 1 << CPU_INSERTING_FLAG)
&& state.inserting
{
state.inserting = false;
}
// Ditto for removal
if (data[0] & (1 << CPU_REMOVING_FLAG) == 1 << CPU_REMOVING_FLAG)
&& state.removing
{
state.removing = false;
}
// Trigger removal of vCPU
if data[0] & (1 << CPU_EJECT_FLAG) == 1 << CPU_EJECT_FLAG {
if let Err(e) = self.remove_vcpu(self.selected_cpu) {
error!("Error removing vCPU: {:?}", e);
}
}
} else {
warn!("Out of range vCPU id: {}", self.selected_cpu);
}
}
_ => {
@@ -546,11 +553,7 @@ impl CpuManager {
.map(|sgx_epc_region| sgx_epc_region.epc_sections().values().cloned().collect());
#[cfg(target_arch = "x86_64")]
let cpuid = {
let phys_bits = physical_bits(
config.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(config.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
config

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::vm::{Error as VmError, Vm, VmState};
use anyhow::anyhow;
use libc::EFD_NONBLOCK;
use memory_manager::MemoryManagerSnapshotData;
use seccompiler::{apply_filter, SeccompAction};
use serde::ser::{Serialize, SerializeStruct, Serializer};
use std::fs::File;
@@ -46,7 +47,10 @@ use vm_migration::{protocol::*, Migratable};
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
#[cfg(feature = "acpi")]
mod acpi;
pub mod api;
mod clone3;
pub mod config;
pub mod cpu;
pub mod device_manager;
@@ -54,12 +58,12 @@ pub mod device_tree;
pub mod interrupt;
pub mod memory_manager;
pub mod migration;
mod pci_segment;
pub mod seccomp_filters;
pub mod vm;
#[cfg(feature = "acpi")]
mod acpi;
mod serial_buffer;
mod serial_manager;
mod sigwinch_listener;
pub mod vm;
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
@@ -147,10 +151,8 @@ pub type Result<T> = result::Result<T, Error>;
pub enum EpollDispatch {
Exit = 0,
Reset = 1,
Stdin = 2,
Api = 3,
ActivateVirtioDevices = 4,
SerialPty = 5,
Api = 2,
ActivateVirtioDevices = 3,
Unknown,
}
@@ -160,10 +162,8 @@ impl From<u64> for EpollDispatch {
match v {
0 => Exit,
1 => Reset,
2 => Stdin,
3 => Api,
4 => ActivateVirtioDevices,
5 => SerialPty,
2 => Api,
3 => ActivateVirtioDevices,
_ => Unknown,
}
}
@@ -182,18 +182,6 @@ impl EpollContext {
Ok(EpollContext { epoll_file })
}
pub fn add_stdin(&mut self) -> result::Result<(), io::Error> {
let dispatch_index = EpollDispatch::Stdin as u64;
epoll::ctl(
self.epoll_file.as_raw_fd(),
epoll::ControlOptions::EPOLL_CTL_ADD,
libc::STDIN_FILENO,
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
)?;
Ok(())
}
fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
where
T: AsRawFd,
@@ -262,30 +250,47 @@ pub fn start_vmm_thread(
get_seccomp_filter(seccomp_action, Thread::Vmm).map_err(Error::CreateSeccompFilter)?;
let vmm_seccomp_action = seccomp_action.clone();
let thread = thread::Builder::new()
.name("vmm".to_string())
.spawn(move || {
// Apply seccomp filter for VMM thread.
if !vmm_seccomp_filter.is_empty() {
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
}
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let thread = {
let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?;
thread::Builder::new()
.name("vmm".to_string())
.spawn(move || {
// Apply seccomp filter for VMM thread.
if !vmm_seccomp_filter.is_empty() {
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
}
let mut vmm = Vmm::new(
vmm_version.to_string(),
api_event,
vmm_seccomp_action,
hypervisor,
)?;
let mut vmm = Vmm::new(
vmm_version.to_string(),
api_event,
vmm_seccomp_action,
hypervisor,
exit_evt,
)?;
vmm.control_loop(Arc::new(api_receiver))
})
.map_err(Error::VmmThreadSpawn)?;
vmm.control_loop(Arc::new(api_receiver))
})
.map_err(Error::VmmThreadSpawn)?
};
// The VMM thread is started, we can start serving HTTP requests
if let Some(http_path) = http_path {
api::start_http_path_thread(http_path, http_api_event, api_sender, seccomp_action)?;
api::start_http_path_thread(
http_path,
http_api_event,
api_sender,
seccomp_action,
exit_evt,
)?;
} else if let Some(http_fd) = http_fd {
api::start_http_fd_thread(http_fd, http_api_event, api_sender, seccomp_action)?;
api::start_http_fd_thread(
http_fd,
http_api_event,
api_sender,
seccomp_action,
exit_evt,
)?;
}
Ok(thread)
}
@@ -295,6 +300,7 @@ struct VmMigrationConfig {
vm_config: Arc<Mutex<VmConfig>>,
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
common_cpuid: hypervisor::CpuId,
memory_manager_data: MemoryManagerSnapshotData,
}
pub struct Vmm {
@@ -316,9 +322,9 @@ impl Vmm {
api_evt: EventFd,
seccomp_action: SeccompAction,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
exit_evt: EventFd,
) -> Result<Self> {
let mut epoll = EpollContext::new().map_err(Error::Epoll)?;
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
@@ -388,19 +394,8 @@ impl Vmm {
activate_evt,
None,
None,
None,
)?;
if let Some(serial_pty) = vm.serial_pty() {
self.epoll
.add_event(&serial_pty.main, EpollDispatch::SerialPty)
.map_err(VmError::EventfdError)?;
};
if matches!(
vm_config.lock().unwrap().serial.mode,
config::ConsoleOutputMode::Tty
) && unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0
{
self.epoll.add_stdin().map_err(VmError::EventfdError)?;
}
self.vm = Some(vm);
}
@@ -515,6 +510,10 @@ impl Vmm {
let config = vm.get_config();
let serial_pty = vm.serial_pty();
let console_pty = vm.console_pty();
let console_resize_pipe = vm
.console_resize_pipe()
.as_ref()
.map(|pipe| pipe.try_clone().unwrap());
self.vm_shutdown()?;
let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
@@ -539,6 +538,7 @@ impl Vmm {
activate_evt,
serial_pty,
console_pty,
console_resize_pipe,
)?);
}
@@ -766,7 +766,7 @@ impl Vmm {
where
T: Read + Write,
{
// Read in config data
// Read in config data along with memory manager data
let mut data = Vec::with_capacity(req.length() as usize);
unsafe {
data.set_len(req.length() as usize);
@@ -804,6 +804,7 @@ impl Vmm {
&self.seccomp_action,
self.hypervisor.clone(),
activate_evt,
&vm_migration_config.memory_manager_data,
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error creating VM from snapshot: {:?}", e))
@@ -1040,11 +1041,7 @@ impl Vmm {
let common_cpuid = {
#[cfg(feature = "tdx")]
let tdx_enabled = vm_config.lock().unwrap().tdx.is_some();
let phys_bits = vm::physical_bits(
vm_config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = vm::physical_bits(vm_config.lock().unwrap().cpus.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
None,
@@ -1063,8 +1060,8 @@ impl Vmm {
vm_config,
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
common_cpuid,
memory_manager_data: vm.memory_manager_data(),
};
let config_data = serde_json::to_vec(&vm_migration_config).unwrap();
Request::config(config_data.len() as u64).write_to(&mut socket)?;
socket
@@ -1212,11 +1209,7 @@ impl Vmm {
#[cfg(feature = "tdx")]
let tdx_enabled = vm_config.tdx.is_some();
let phys_bits = vm::physical_bits(
vm_config.cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = vm::physical_bits(vm_config.cpus.max_phys_bits);
arch::generate_common_cpuid(
self.hypervisor.clone(),
None,
@@ -1283,11 +1276,6 @@ impl Vmm {
self.reset_evt.read().map_err(Error::EventFdRead)?;
self.vm_reboot().map_err(Error::VmReboot)?;
}
EpollDispatch::Stdin => {
if let Some(ref vm) = self.vm {
vm.handle_stdin().map_err(Error::Stdin)?;
}
}
EpollDispatch::ActivateVirtioDevices => {
if let Some(ref vm) = self.vm {
let count = self.activate_evt.read().map_err(Error::EventFdRead)?;
@@ -1299,11 +1287,6 @@ impl Vmm {
.map_err(Error::ActivateVirtioDevices)?;
}
}
event @ EpollDispatch::SerialPty => {
if let Some(ref vm) = self.vm {
vm.handle_pty(event).map_err(Error::Pty)?;
}
}
EpollDispatch::Api => {
// Consume the event.
self.api_evt.read().map_err(Error::EventFdRead)?;

File diff suppressed because it is too large Load Diff

131
vmm/src/pci_segment.rs Normal file
View File

@@ -0,0 +1,131 @@
// Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
//
// Copyright © 2019 - 2021 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
//
use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult};
use pci::{DeviceRelocation, PciBus, PciConfigMmio, PciRoot};
#[cfg(target_arch = "x86_64")]
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
use std::sync::{Arc, Mutex};
use vm_device::BusDevice;
pub(crate) struct PciSegment {
id: u16,
pub(crate) pci_bus: Arc<Mutex<PciBus>>,
pub(crate) pci_config_mmio: Arc<Mutex<PciConfigMmio>>,
mmio_config_address: u64,
#[cfg(target_arch = "x86_64")]
pub(crate) pci_config_io: Option<Arc<Mutex<PciConfigIo>>>,
// Bitmap of PCI devices to hotplug.
pub(crate) pci_devices_up: u32,
// Bitmap of PCI devices to hotunplug.
pub(crate) pci_devices_down: u32,
// List of allocated IRQs for each PCI slot.
pub(crate) pci_irq_slots: [u8; 32],
}
impl PciSegment {
pub(crate) fn new_default_segment(
address_manager: &Arc<AddressManager>,
) -> DeviceManagerResult<PciSegment> {
let pci_root = PciRoot::new(None);
let pci_bus = Arc::new(Mutex::new(PciBus::new(
pci_root,
Arc::clone(address_manager) as Arc<dyn DeviceRelocation>,
)));
let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus))));
address_manager
.mmio_bus
.insert(
Arc::clone(&pci_config_mmio) as Arc<Mutex<dyn BusDevice>>,
arch::layout::PCI_MMCONFIG_START.0,
arch::layout::PCI_MMCONFIG_SIZE,
)
.map_err(DeviceManagerError::BusError)?;
#[cfg(target_arch = "x86_64")]
let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&pci_bus))));
#[cfg(target_arch = "x86_64")]
address_manager
.io_bus
.insert(
pci_config_io.clone(),
PCI_CONFIG_IO_PORT,
PCI_CONFIG_IO_PORT_SIZE,
)
.map_err(DeviceManagerError::BusError)?;
let mut segment = PciSegment {
id: 0,
pci_bus,
pci_config_mmio,
mmio_config_address: arch::layout::PCI_MMCONFIG_START.0,
pci_devices_up: 0,
pci_devices_down: 0,
pci_irq_slots: [0; 32],
#[cfg(target_arch = "x86_64")]
pci_config_io: Some(pci_config_io),
};
// Reserve some IRQs for PCI devices in case they need to support INTx.
segment.reserve_legacy_interrupts_for_pci_devices(address_manager)?;
info!(
"Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}",
segment.id, segment.mmio_config_address
);
Ok(segment)
}
pub(crate) fn next_device_bdf(&self) -> DeviceManagerResult<u32> {
// We need to shift the device id since the 3 first bits
// are dedicated to the PCI function, and we know we don't
// do multifunction. Also, because we only support one PCI
// bus, the bus 0, we don't need to add anything to the
// global device ID.
Ok(self
.pci_bus
.lock()
.unwrap()
.next_device_id()
.map_err(DeviceManagerError::NextPciDeviceId)?
<< 3)
}
fn reserve_legacy_interrupts_for_pci_devices(
&mut self,
address_manager: &Arc<AddressManager>,
) -> DeviceManagerResult<()> {
// Reserve 8 IRQs which will be shared across all PCI devices.
let num_irqs = 8;
let mut irqs: Vec<u8> = Vec::new();
for _ in 0..num_irqs {
irqs.push(
address_manager
.allocator
.lock()
.unwrap()
.allocate_irq()
.ok_or(DeviceManagerError::AllocateIrq)? as u8,
);
}
// There are 32 devices on the PCI bus, let's assign them an IRQ.
for i in 0..32 {
self.pci_irq_slots[i] = irqs[(i % num_irqs) as usize];
}
Ok(())
}
}

View File

@@ -15,6 +15,7 @@ pub enum Thread {
SignalHandler,
Vcpu,
Vmm,
PtyForeground,
}
/// Shorthand for chaining `SeccompCondition`s with the `and` operator in a `SeccompRule`.
@@ -39,6 +40,8 @@ macro_rules! or {
// See include/uapi/asm-generic/ioctls.h in the kernel code.
const TCGETS: u64 = 0x5401;
const TCSETS: u64 = 0x5402;
const TIOCSCTTY: u64 = 0x540E;
const TIOCSPGRP: u64 = 0x5410;
const TIOCGWINSZ: u64 = 0x5413;
const TIOCSPTLCK: u64 = 0x4004_5431;
const TIOCGTPEER: u64 = 0x5441;
@@ -217,9 +220,11 @@ fn create_vmm_ioctl_seccomp_rule_common() -> Result<Vec<SeccompRule>, BackendErr
and![Cond::new(1, ArgLen::Dword, Eq, SIOCSIFNETMASK)?],
and![Cond::new(1, ArgLen::Dword, Eq, TCSETS)?],
and![Cond::new(1, ArgLen::Dword, Eq, TCGETS)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPTLCK)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGTPEER)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPGRP)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPTLCK)?],
and![Cond::new(1, ArgLen::Dword, Eq, TUNGETFEATURES)?],
and![Cond::new(1, ArgLen::Dword, Eq, TUNGETIFF)?],
and![Cond::new(1, ArgLen::Dword, Eq, TUNSETIFF)?],
@@ -356,6 +361,7 @@ fn signal_handler_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
(libc::SYS_futex, vec![]),
(libc::SYS_ioctl, create_signal_handler_ioctl_seccomp_rule()?),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
@@ -366,6 +372,35 @@ fn signal_handler_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
])
}
fn create_pty_foreground_ioctl_seccomp_rule() -> Result<Vec<SeccompRule>, BackendError> {
Ok(or![
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPGRP)?],
])
}
fn pty_foreground_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
Ok(vec![
(libc::SYS_close, vec![]),
(libc::SYS_exit_group, vec![]),
(libc::SYS_getpgid, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_getpgrp, vec![]),
(libc::SYS_ioctl, create_pty_foreground_ioctl_seccomp_rule()?),
(libc::SYS_munmap, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_poll, vec![]),
#[cfg(target_arch = "aarch64")]
(libc::SYS_ppoll, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigaction, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_setsid, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
])
}
// The filter containing the white listed syscall rules required by the VMM to
// function.
fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
@@ -380,6 +415,7 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_clock_nanosleep, vec![]),
(libc::SYS_clone, vec![]),
(libc::SYS_clone3, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_connect, vec![]),
(libc::SYS_dup, vec![]),
@@ -405,6 +441,9 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
#[cfg(target_arch = "aarch64")]
(libc::SYS_newfstatat, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_getpgid, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_getpgrp, vec![]),
(libc::SYS_getpid, vec![]),
(libc::SYS_getrandom, vec![]),
(libc::SYS_gettid, vec![]),
@@ -430,6 +469,10 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
(libc::SYS_open, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_pipe2, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_poll, vec![]),
#[cfg(target_arch = "aarch64")]
(libc::SYS_ppoll, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_pread64, vec![]),
(libc::SYS_preadv, vec![]),
@@ -453,6 +496,7 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
(libc::SYS_sendto, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_set_tid_address, vec![]),
(libc::SYS_setsid, vec![]),
(libc::SYS_sigaltstack, vec![]),
(
libc::SYS_socket,
@@ -598,6 +642,7 @@ fn api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
(libc::SYS_getrandom, vec![]),
(libc::SYS_ioctl, create_api_ioctl_seccomp_rule()?),
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_recvfrom, vec![]),
@@ -613,6 +658,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Result<Vec<(i64, Vec<SeccompRule>)>
Thread::SignalHandler => Ok(signal_handler_thread_rules()?),
Thread::Vcpu => Ok(vcpu_thread_rules()?),
Thread::Vmm => Ok(vmm_thread_rules()?),
Thread::PtyForeground => Ok(pty_foreground_thread_rules()?),
}
}

View File

@@ -3,7 +3,10 @@
// SPDX-License-Identifier: Apache-2.0
//
use crate::serial_manager::EpollDispatch;
use std::io::Write;
use std::os::unix::io::RawFd;
// Circular buffer implementation for serial output.
// Read from head; push to tail
@@ -12,6 +15,9 @@ pub(crate) struct SerialBuffer {
head: usize,
tail: usize,
out: Box<dyn Write + Send>,
buffering: bool,
out_fd: Option<RawFd>,
epoll_fd: Option<RawFd>,
}
const MAX_BUFFER_SIZE: usize = 16 << 10;
@@ -23,10 +29,21 @@ impl SerialBuffer {
head: 0,
tail: 0,
out,
buffering: false,
out_fd: None,
epoll_fd: None,
}
}
pub(crate) fn flush_buffer(&mut self) -> Result<(), std::io::Error> {
pub(crate) fn add_out_fd(&mut self, out_fd: RawFd) {
self.out_fd = Some(out_fd);
}
pub(crate) fn add_epoll_fd(&mut self, epoll_fd: RawFd) {
self.epoll_fd = Some(epoll_fd);
}
pub fn flush_buffer(&mut self) -> Result<(), std::io::Error> {
if self.tail <= self.head {
// The buffer to be written is in two parts
let buf = &self.buffer[self.head..];
@@ -45,6 +62,7 @@ impl SerialBuffer {
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
return Err(e);
}
self.add_out_poll()?;
return Ok(());
}
}
@@ -58,6 +76,7 @@ impl SerialBuffer {
self.buffer.shrink_to_fit();
self.head = 0;
self.tail = 0;
self.remove_out_poll()?;
} else {
self.head += bytes_written;
}
@@ -67,11 +86,45 @@ impl SerialBuffer {
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
return Err(e);
}
self.add_out_poll()?;
}
}
Ok(())
}
fn add_out_poll(&mut self) -> Result<(), std::io::Error> {
if self.out_fd.is_some() && self.epoll_fd.is_some() && !self.buffering {
self.buffering = true;
let out_fd = self.out_fd.as_ref().unwrap();
let epoll_fd = self.epoll_fd.as_ref().unwrap();
epoll::ctl(
*epoll_fd,
epoll::ControlOptions::EPOLL_CTL_MOD,
*out_fd,
epoll::Event::new(
epoll::Events::EPOLLIN | epoll::Events::EPOLLOUT,
EpollDispatch::File as u64,
),
)?;
}
Ok(())
}
fn remove_out_poll(&mut self) -> Result<(), std::io::Error> {
if self.out_fd.is_some() && self.epoll_fd.is_some() && self.buffering {
self.buffering = false;
let out_fd = self.out_fd.as_ref().unwrap();
let epoll_fd = self.epoll_fd.as_ref().unwrap();
epoll::ctl(
*epoll_fd,
epoll::ControlOptions::EPOLL_CTL_MOD,
*out_fd,
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::File as u64),
)?;
}
Ok(())
}
}
impl Write for SerialBuffer {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
@@ -83,6 +136,7 @@ impl Write for SerialBuffer {
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
return Err(e);
}
self.add_out_poll()?;
self.buffer.push(*v);
self.tail += 1;
} else {
@@ -116,6 +170,6 @@ impl Write for SerialBuffer {
}
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
self.flush_buffer()
}
}

270
vmm/src/serial_manager.rs Normal file
View File

@@ -0,0 +1,270 @@
// Copyright © 2021 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
use crate::config::ConsoleOutputMode;
use crate::device_manager::PtyPair;
use crate::serial_buffer::SerialBuffer;
#[cfg(target_arch = "aarch64")]
use devices::legacy::Pl011;
#[cfg(target_arch = "x86_64")]
use devices::legacy::Serial;
use libc::EFD_NONBLOCK;
use std::fs::File;
use std::io::Read;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::panic::AssertUnwindSafe;
use std::sync::{Arc, Mutex};
use std::{io, result, thread};
use thiserror::Error;
use vmm_sys_util::eventfd::EventFd;
#[derive(Debug, Error)]
pub enum Error {
/// Cannot clone File.
#[error("Error cloning File: {0}")]
FileClone(#[source] io::Error),
/// Cannot create epoll context.
#[error("Error creating epoll context: {0}")]
Epoll(#[source] io::Error),
/// Cannot handle the VM input stream.
#[error("Error handling VM input: {0:?}")]
ReadInput(#[source] io::Error),
/// Cannot queue input to the serial device.
#[error("Error queuing input to the serial device: {0}")]
QueueInput(#[source] vmm_sys_util::errno::Error),
/// Cannot flush output on the serial buffer.
#[error("Error flushing serial device's output buffer: {0}")]
FlushOutput(#[source] io::Error),
/// Cannot make the file descriptor non-blocking.
#[error("Error making input file descriptor non-blocking: {0}")]
SetNonBlocking(#[source] io::Error),
/// Cannot create EventFd.
#[error("Error creating EventFd: {0}")]
EventFd(#[source] io::Error),
/// Cannot spawn SerialManager thread.
#[error("Error spawning SerialManager thread: {0}")]
SpawnSerialManager(#[source] io::Error),
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u64)]
pub enum EpollDispatch {
File = 0,
Kill = 1,
Unknown,
}
impl From<u64> for EpollDispatch {
fn from(v: u64) -> Self {
use EpollDispatch::*;
match v {
0 => File,
1 => Kill,
_ => Unknown,
}
}
}
pub struct SerialManager {
#[cfg(target_arch = "x86_64")]
serial: Arc<Mutex<Serial>>,
#[cfg(target_arch = "aarch64")]
serial: Arc<Mutex<Pl011>>,
epoll_file: File,
in_file: File,
kill_evt: EventFd,
handle: Option<thread::JoinHandle<()>>,
}
impl SerialManager {
pub fn new(
#[cfg(target_arch = "x86_64")] serial: Arc<Mutex<Serial>>,
#[cfg(target_arch = "aarch64")] serial: Arc<Mutex<Pl011>>,
pty_pair: Option<Arc<Mutex<PtyPair>>>,
mode: ConsoleOutputMode,
) -> Result<Option<Self>> {
let in_file = match mode {
ConsoleOutputMode::Pty => {
if let Some(pty_pair) = pty_pair {
pty_pair
.lock()
.unwrap()
.main
.try_clone()
.map_err(Error::FileClone)?
} else {
return Ok(None);
}
}
ConsoleOutputMode::Tty => {
// If running on an interactive TTY then accept input
if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } {
let stdin_clone = unsafe { File::from_raw_fd(libc::dup(libc::STDIN_FILENO)) };
let ret = unsafe {
let mut flags = libc::fcntl(stdin_clone.as_raw_fd(), libc::F_GETFL);
flags |= libc::O_NONBLOCK;
libc::fcntl(stdin_clone.as_raw_fd(), libc::F_SETFL, flags)
};
if ret < 0 {
return Err(Error::SetNonBlocking(std::io::Error::last_os_error()));
}
stdin_clone
} else {
return Ok(None);
}
}
_ => return Ok(None),
};
let epoll_fd = epoll::create(true).map_err(Error::Epoll)?;
let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?;
epoll::ctl(
epoll_fd,
epoll::ControlOptions::EPOLL_CTL_ADD,
kill_evt.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Kill as u64),
)
.map_err(Error::Epoll)?;
epoll::ctl(
epoll_fd,
epoll::ControlOptions::EPOLL_CTL_ADD,
in_file.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::File as u64),
)
.map_err(Error::Epoll)?;
if mode == ConsoleOutputMode::Pty {
let writer = in_file.try_clone().map_err(Error::FileClone)?;
let mut buffer = SerialBuffer::new(Box::new(writer));
buffer.add_out_fd(in_file.as_raw_fd());
buffer.add_epoll_fd(epoll_fd);
serial.as_ref().lock().unwrap().set_out(Box::new(buffer));
}
// Use 'File' to enforce closing on 'epoll_fd'
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
Ok(Some(SerialManager {
serial,
epoll_file,
in_file,
kill_evt,
handle: None,
}))
}
pub fn start_thread(&mut self, exit_evt: EventFd) -> Result<()> {
// Don't allow this to be run if the handle exists
if self.handle.is_some() {
warn!("Tried to start multiple SerialManager threads, ignoring");
return Ok(());
}
let epoll_fd = self.epoll_file.as_raw_fd();
let mut in_file = self.in_file.try_clone().map_err(Error::FileClone)?;
let serial = self.serial.clone();
let thread = thread::Builder::new()
.name("serial-manager".to_string())
.spawn(move || {
std::panic::catch_unwind(AssertUnwindSafe(move || {
// 3 for File, Kill, and Unknown
const EPOLL_EVENTS_LEN: usize = 3;
let mut events =
vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
loop {
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
Ok(res) => res,
Err(e) => {
if e.kind() == io::ErrorKind::Interrupted {
// It's well defined from the epoll_wait() syscall
// documentation that the epoll loop can be interrupted
// before any of the requested events occurred or the
// timeout expired. In both those cases, epoll_wait()
// returns an error of type EINTR, but this should not
// be considered as a regular error. Instead it is more
// appropriate to retry, by calling into epoll_wait().
continue;
}
return Err(Error::Epoll(e));
}
};
for event in events.iter().take(num_events) {
let dispatch_event: EpollDispatch = event.data.into();
match dispatch_event {
EpollDispatch::Unknown => {
let event = event.data;
warn!("Unknown serial manager loop event: {}", event);
}
EpollDispatch::File => {
if event.events & libc::EPOLLOUT as u32 != 0 {
serial
.as_ref()
.lock()
.unwrap()
.flush_output()
.map_err(Error::FlushOutput)?;
}
if event.events & libc::EPOLLIN as u32 != 0 {
let mut input = [0u8; 64];
let count =
in_file.read(&mut input).map_err(Error::ReadInput)?;
// Replace "\n" with "\r" to deal with Windows SAC (#1170)
if count == 1 && input[0] == 0x0a {
input[0] = 0x0d;
}
serial
.as_ref()
.lock()
.unwrap()
.queue_input_bytes(&input[..count])
.map_err(Error::QueueInput)?;
}
}
EpollDispatch::Kill => {
info!("KILL event received, stopping epoll loop");
return Ok(());
}
}
}
}
}))
.map_err(|_| {
error!("serial-manager thread panicked");
exit_evt.write(1).ok()
})
.ok();
})
.map_err(Error::SpawnSerialManager)?;
self.handle = Some(thread);
Ok(())
}
}
impl Drop for SerialManager {
fn drop(&mut self) {
self.kill_evt.write(1).ok();
if let Some(handle) = self.handle.take() {
handle.join().ok();
}
}
}

View File

@@ -0,0 +1,135 @@
// Copyright 2021 Alyssa Ross <hi@alyssa.is>
// SPDX-License-Identifier: Apache-2.0
use crate::clone3::{clone3, clone_args, CLONE_CLEAR_SIGHAND};
use libc::{
c_int, c_void, close, getpgrp, ioctl, pipe2, poll, pollfd, setsid, sigemptyset, siginfo_t,
sigprocmask, tcsetpgrp, O_CLOEXEC, POLLERR, SIGWINCH, SIG_SETMASK, STDIN_FILENO, STDOUT_FILENO,
TIOCSCTTY,
};
use seccompiler::{apply_filter, BpfProgram};
use std::cell::RefCell;
use std::fs::File;
use std::io::{self, ErrorKind, Read, Write};
use std::mem::size_of;
use std::mem::MaybeUninit;
use std::os::unix::prelude::*;
use std::process::exit;
use std::ptr::null_mut;
use vmm_sys_util::signal::register_signal_handler;
thread_local! {
// The tty file descriptor is stored in a global variable so it
// can be accessed by a signal handler.
static TX: RefCell<Option<File>> = RefCell::new(None);
}
fn with_tx<R, F: FnOnce(&File) -> R>(f: F) -> R {
TX.with(|tx| f(tx.borrow().as_ref().unwrap()))
}
// This function has to be safe to call from a signal handler, and
// therefore must not panic.
fn notify() {
if let Err(e) = with_tx(|mut tx| tx.write_all(b"\n")) {
if e.kind() == ErrorKind::BrokenPipe {
exit(0);
}
exit(1);
}
}
extern "C" fn sigwinch_handler(_signo: c_int, _info: *mut siginfo_t, _unused: *mut c_void) {
notify();
}
fn unblock_all_signals() -> io::Result<()> {
let mut set = MaybeUninit::uninit();
if unsafe { sigemptyset(set.as_mut_ptr()) } == -1 {
return Err(io::Error::last_os_error());
}
let set = unsafe { set.assume_init() };
if unsafe { sigprocmask(SIG_SETMASK, &set, null_mut()) } == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
}
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, tty: &File) -> ! {
TX.with(|opt| opt.replace(Some(tx)));
unsafe {
close(STDIN_FILENO);
close(STDOUT_FILENO);
}
unblock_all_signals().unwrap();
apply_filter(&seccomp_filter).unwrap();
register_signal_handler(SIGWINCH, sigwinch_handler).unwrap();
unsafe {
// Create a new session (and therefore a new process group).
assert_ne!(setsid(), -1);
// Set the tty to be this process's controlling terminal.
assert_ne!(ioctl(tty.as_raw_fd(), TIOCSCTTY, 0), -1);
// Become the foreground process group of the tty.
assert_ne!(tcsetpgrp(tty.as_raw_fd(), getpgrp()), -1);
}
notify();
// Wait for the pipe to close, indicating the parent has exited.
with_tx(|tx| {
let mut pollfd = pollfd {
fd: tx.as_raw_fd(),
events: 0,
revents: 0,
};
while unsafe { poll(&mut pollfd, 1, -1) } == -1 {
let e = io::Error::last_os_error();
if !matches!(e.kind(), ErrorKind::Interrupted | ErrorKind::WouldBlock) {
panic!("poll: {}", e);
}
}
assert_eq!(pollfd.revents, POLLERR);
});
exit(0);
}
pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, pty: &File) -> io::Result<File> {
let mut pipe = [-1; 2];
if unsafe { pipe2(pipe.as_mut_ptr(), O_CLOEXEC) } == -1 {
return Err(io::Error::last_os_error());
}
let mut rx = unsafe { File::from_raw_fd(pipe[0]) };
let tx = unsafe { File::from_raw_fd(pipe[1]) };
let mut args = clone_args::default();
args.flags |= CLONE_CLEAR_SIGHAND;
match unsafe { clone3(&mut args, size_of::<clone_args>()) } {
-1 => return Err(io::Error::last_os_error()),
0 => {
drop(rx);
sigwinch_listener_main(seccomp_filter, tx, pty);
}
_ => (),
}
drop(tx);
// Wait for a notification indicating readiness.
rx.read_exact(&mut [0])?;
Ok(rx)
}

View File

@@ -14,25 +14,27 @@
#[cfg(any(target_arch = "aarch64", feature = "acpi"))]
use crate::config::NumaConfig;
use crate::config::{
ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig,
UserDeviceConfig, ValidationError, VmConfig, VsockConfig,
};
use crate::device_manager::{
self, get_win_size, Console, DeviceManager, DeviceManagerError, PtyPair,
DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig, UserDeviceConfig,
ValidationError, VmConfig, VsockConfig,
};
use crate::cpu;
use crate::device_manager::{self, Console, DeviceManager, DeviceManagerError, PtyPair};
use crate::device_tree::DeviceTree;
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
use crate::memory_manager::{
Error as MemoryManagerError, MemoryManager, MemoryManagerSnapshotData,
};
use crate::migration::{get_vm_snapshot, url_to_path, VM_SNAPSHOT_FILE};
use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::GuestMemoryMmap;
use crate::{cpu, EpollDispatch};
use crate::{
PciDeviceInfo, CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID,
};
use anyhow::anyhow;
use arch::get_host_cpu_phys_bits;
#[cfg(all(feature = "tdx", feature = "acpi"))]
use arch::x86_64::tdx::TdVmmDataRegionType;
#[cfg(feature = "tdx")]
use arch::x86_64::tdx::TdvfSection;
use arch::x86_64::tdx::{TdVmmDataRegion, TdvfSection};
use arch::EntryPoint;
#[cfg(any(target_arch = "aarch64", feature = "acpi"))]
use arch::{NumaNode, NumaNodes};
@@ -55,7 +57,6 @@ use std::cmp;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::convert::TryInto;
use std::ffi::CString;
#[cfg(target_arch = "x86_64")]
use std::fmt;
use std::fs::{File, OpenOptions};
@@ -67,14 +68,16 @@ use std::panic::AssertUnwindSafe;
use std::sync::{Arc, Mutex, RwLock};
use std::{result, str, thread};
use vm_device::Bus;
use vm_memory::{
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
GuestMemoryRegion,
};
#[cfg(target_arch = "x86_64")]
use vm_device::BusDevice;
#[cfg(any(target_arch = "aarch64", feature = "tdx"))]
use vm_memory::Address;
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
#[cfg(feature = "tdx")]
use vm_memory::{GuestMemory, GuestMemoryRegion};
use vm_migration::{
protocol::{MemoryRange, MemoryRangeTable},
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
Transportable,
protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot,
SnapshotDataSection, Snapshottable, Transportable,
};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::unblock_signal;
@@ -112,9 +115,6 @@ pub enum Error {
/// Cannot modify the command line
CmdLineInsertStr(linux_loader::cmdline::Error),
/// Cannot convert command line into CString
CmdLineCString(std::ffi::NulError),
/// Cannot configure system
ConfigureSystem(arch::Error),
@@ -362,6 +362,8 @@ struct VmOps {
mmio_bus: Arc<Bus>,
#[cfg(target_arch = "x86_64")]
timestamp: std::time::Instant,
#[cfg(target_arch = "x86_64")]
pci_config_io: Arc<Mutex<dyn BusDevice>>,
}
impl VmOps {
@@ -419,6 +421,17 @@ impl VmmOps for VmOps {
#[cfg(target_arch = "x86_64")]
fn pio_read(&self, port: u64, data: &mut [u8]) -> hypervisor::vm::Result<()> {
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
self.pci_config_io.lock().unwrap().read(
PCI_CONFIG_IO_PORT,
port - PCI_CONFIG_IO_PORT,
data,
);
return Ok(());
}
if let Err(vm_device::BusError::MissingAddressRange) = self.io_bus.read(port, data) {
warn!("Guest PIO read to unregistered address 0x{:x}", port);
}
@@ -427,11 +440,22 @@ impl VmmOps for VmOps {
#[cfg(target_arch = "x86_64")]
fn pio_write(&self, port: u64, data: &[u8]) -> hypervisor::vm::Result<()> {
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
if port == DEBUG_IOPORT as u64 && data.len() == 1 {
self.log_debug_ioport(data[0]);
return Ok(());
}
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
self.pci_config_io.lock().unwrap().write(
PCI_CONFIG_IO_PORT,
port - PCI_CONFIG_IO_PORT,
data,
);
return Ok(());
}
match self.io_bus.write(port, data) {
Err(vm_device::BusError::MissingAddressRange) => {
warn!("Guest PIO write to unregistered address 0x{:x}", port);
@@ -447,24 +471,10 @@ impl VmmOps for VmOps {
}
}
pub fn physical_bits(max_phys_bits: Option<u8>, #[cfg(feature = "tdx")] tdx_enabled: bool) -> u8 {
#[cfg(not(feature = "tdx"))]
pub fn physical_bits(max_phys_bits: u8) -> u8 {
let host_phys_bits = get_host_cpu_phys_bits();
#[cfg(feature = "tdx")]
let mut host_phys_bits = get_host_cpu_phys_bits();
#[cfg(feature = "tdx")]
if tdx_enabled {
// When running TDX guest, the Guest Physical Address space is limited
// by a shared bit that is located on bit 47 for 4 level paging, and on
// bit 51 for 5 level paging (when GPAW bit is 1). In order to keep
// things simple, and since a 47 bits address space is 128TiB large, we
// ensure to limit the physical addressable space to 47 bits when
// runnning TDX.
host_phys_bits = std::cmp::min(host_phys_bits, 47)
}
cmp::min(host_phys_bits, max_phys_bits.unwrap_or(host_phys_bits))
cmp::min(host_phys_bits, max_phys_bits)
}
pub const HANDLED_SIGNALS: [i32; 3] = [SIGWINCH, SIGTERM, SIGINT];
@@ -548,6 +558,10 @@ impl Vm {
let mmio_bus = Arc::clone(device_manager.lock().unwrap().mmio_bus());
// Create the VmOps structure, which implements the VmmOps trait.
// And send it to the hypervisor.
#[cfg(target_arch = "x86_64")]
let pci_config_io =
device_manager.lock().unwrap().pci_config_io() as Arc<Mutex<dyn BusDevice>>;
let vm_ops: Arc<dyn VmmOps> = Arc::new(VmOps {
memory,
#[cfg(target_arch = "x86_64")]
@@ -555,6 +569,8 @@ impl Vm {
mmio_bus,
#[cfg(target_arch = "x86_64")]
timestamp: std::time::Instant::now(),
#[cfg(target_arch = "x86_64")]
pci_config_io,
});
let exit_evt_clone = exit_evt.try_clone().map_err(Error::EventFdClone)?;
@@ -710,6 +726,7 @@ impl Vm {
activate_evt: EventFd,
serial_pty: Option<PtyPair>,
console_pty: Option<PtyPair>,
console_resize_pipe: Option<File>,
) -> Result<Self> {
#[cfg(feature = "tdx")]
let tdx_enabled = config.lock().unwrap().tdx.is_some();
@@ -727,18 +744,15 @@ impl Vm {
#[cfg(target_arch = "x86_64")]
vm.enable_split_irq().unwrap();
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
let memory_manager = MemoryManager::new(
vm.clone(),
&config.lock().unwrap().memory.clone(),
false,
None,
phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
None,
)
.map_err(Error::MemoryManager)?;
@@ -773,7 +787,7 @@ impl Vm {
.device_manager
.lock()
.unwrap()
.create_devices(serial_pty, console_pty)
.create_devices(serial_pty, console_pty, console_resize_pipe)
.map_err(Error::DeviceManager)?;
Ok(new_vm)
}
@@ -803,11 +817,7 @@ impl Vm {
let memory_manager = if let Some(memory_manager_snapshot) =
snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID)
{
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
config.lock().unwrap().tdx.is_some(),
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
MemoryManager::new_from_snapshot(
memory_manager_snapshot,
vm.clone(),
@@ -845,24 +855,22 @@ impl Vm {
seccomp_action: &SeccompAction,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
activate_evt: EventFd,
memory_manager_data: &MemoryManagerSnapshotData,
) -> Result<Self> {
hypervisor.check_required_extensions().unwrap();
let vm = hypervisor.create_vm().unwrap();
#[cfg(target_arch = "x86_64")]
vm.enable_split_irq().unwrap();
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
config.lock().unwrap().tdx.is_some(),
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
let memory_manager = MemoryManager::new(
vm.clone(),
&config.lock().unwrap().memory.clone(),
false,
None,
phys_bits,
#[cfg(feature = "tdx")]
false,
Some(memory_manager_data),
)
.map_err(Error::MemoryManager)?;
@@ -904,7 +912,7 @@ impl Vm {
Ok(arch::InitramfsConfig { address, size })
}
fn get_cmdline(&mut self) -> Result<CString> {
fn get_cmdline(&mut self) -> Result<Cmdline> {
let mut cmdline = Cmdline::new(arch::CMDLINE_MAX_SIZE);
cmdline
.insert_str(self.config.lock().unwrap().cmdline.args.clone())
@@ -912,7 +920,7 @@ impl Vm {
for entry in self.device_manager.lock().unwrap().cmdline_additions() {
cmdline.insert_str(entry).map_err(Error::CmdLineInsertStr)?;
}
CString::new(cmdline).map_err(Error::CmdLineCString)
Ok(cmdline)
}
#[cfg(target_arch = "aarch64")]
@@ -957,7 +965,7 @@ impl Vm {
#[cfg(target_arch = "x86_64")]
fn load_kernel(&mut self) -> Result<EntryPoint> {
info!("Loading kernel");
let cmdline_cstring = self.get_cmdline()?;
let cmdline = self.get_cmdline()?;
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
let mem = guest_memory.memory();
let mut kernel = self.kernel.as_ref().unwrap();
@@ -973,12 +981,8 @@ impl Vm {
}
};
linux_loader::loader::load_cmdline(
mem.deref(),
arch::layout::CMDLINE_START,
&cmdline_cstring,
)
.map_err(Error::LoadCmdLine)?;
linux_loader::loader::load_cmdline(mem.deref(), arch::layout::CMDLINE_START, &cmdline)
.map_err(Error::LoadCmdLine)?;
if let PvhEntryPresent(entry_addr) = entry_addr.pvh_boot_cap {
// Use the PVH kernel entry point to boot the guest
@@ -990,7 +994,7 @@ impl Vm {
}
#[cfg(target_arch = "x86_64")]
fn configure_system(&mut self) -> Result<()> {
fn configure_system(&mut self, #[cfg(feature = "acpi")] rsdp_addr: GuestAddress) -> Result<()> {
info!("Configuring system");
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
@@ -1001,23 +1005,10 @@ impl Vm {
let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus();
#[allow(unused_mut, unused_assignments)]
let mut rsdp_addr: Option<GuestAddress> = None;
#[cfg(feature = "acpi")]
{
rsdp_addr = Some(crate::acpi::create_acpi_tables(
&mem,
&self.device_manager,
&self.cpu_manager,
&self.memory_manager,
&self.numa_nodes,
));
info!(
"Created ACPI tables: rsdp_addr = 0x{:x}",
rsdp_addr.unwrap().0
);
}
let rsdp_addr = Some(rsdp_addr);
#[cfg(not(feature = "acpi"))]
let rsdp_addr = None;
let sgx_epc_region = self
.memory_manager
@@ -1040,8 +1031,11 @@ impl Vm {
}
#[cfg(target_arch = "aarch64")]
fn configure_system(&mut self) -> Result<()> {
let cmdline_cstring = self.get_cmdline()?;
fn configure_system(
&mut self,
#[cfg(feature = "acpi")] _rsdp_addr: GuestAddress,
) -> Result<()> {
let cmdline = self.get_cmdline()?;
let vcpu_mpidrs = self.cpu_manager.lock().unwrap().get_mpidrs();
let vcpu_topology = self.cpu_manager.lock().unwrap().get_vcpu_topology();
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
@@ -1078,16 +1072,13 @@ impl Vm {
let pci_space = (pci_space_start.0, pci_space_size);
#[cfg(feature = "acpi")]
{
let _ = crate::acpi::create_acpi_tables(
&mem,
&self.device_manager,
&self.cpu_manager,
&self.memory_manager,
&self.numa_nodes,
);
}
let virtio_iommu_bdf = self
.device_manager
.lock()
.unwrap()
.iommu_attached_devices()
.as_ref()
.map(|(v, _)| *v);
let gic_device = create_gic(
&self.memory_manager.lock().as_ref().unwrap().vm,
@@ -1099,12 +1090,13 @@ impl Vm {
arch::configure_system(
&mem,
&cmdline_cstring,
cmdline.as_str(),
vcpu_mpidrs,
vcpu_topology,
device_info,
&initramfs_config,
&pci_space,
virtio_iommu_bdf,
&*gic_device,
&self.numa_nodes,
)
@@ -1142,6 +1134,10 @@ impl Vm {
self.device_manager.lock().unwrap().console_pty()
}
pub fn console_resize_pipe(&self) -> Option<Arc<File>> {
self.device_manager.lock().unwrap().console_resize_pipe()
}
pub fn shutdown(&mut self) -> Result<()> {
let mut state = self.state.try_write().map_err(|_| Error::PoisonedState)?;
let new_state = VmState::Shutdown;
@@ -1602,8 +1598,7 @@ impl Vm {
for signal in signals.forever() {
match signal {
SIGWINCH => {
let (col, row) = get_win_size();
console_input_clone.update_console_size(col, row);
console_input_clone.update_console_size();
}
SIGTERM | SIGINT => {
if on_tty {
@@ -1644,7 +1639,11 @@ impl Vm {
}
#[cfg(feature = "tdx")]
fn populate_tdx_sections(&mut self, sections: &[TdvfSection]) -> Result<Option<u64>> {
fn populate_tdx_sections(
&mut self,
sections: &[TdvfSection],
vmm_data_regions: &[TdVmmDataRegion],
) -> Result<Option<u64>> {
use arch::x86_64::tdx::*;
// Get the memory end *before* we start adding TDVF ram regions
let boot_guest_memory = self
@@ -1710,6 +1709,20 @@ impl Vm {
sorted_sections.retain(|section| {
!matches!(section.r#type, TdvfSectionType::Bfv | TdvfSectionType::Cfv)
});
// Add VMM specific data memory region to TdvfSections as TdHob type
// to ensure the firmware won't ignore/reject the ranges.
for region in vmm_data_regions {
sorted_sections.push(TdvfSection {
data_offset: 0,
data_size: 0,
address: region.start_address,
size: region.length,
r#type: TdvfSectionType::TdHob,
attributes: 0,
});
}
sorted_sections.sort_by_key(|section| section.address);
sorted_sections.reverse();
let mut current_section = sorted_sections.pop();
@@ -1777,13 +1790,25 @@ impl Vm {
)
.map_err(Error::PopulateHob)?;
// Add VMM specific data to the TdHob. The content of the data is
// is written as part of the HOB, which will be retrieved from the
// firmware, and processed accordingly to the type.
for region in vmm_data_regions {
hob.add_td_vmm_data(&mem, *region)
.map_err(Error::PopulateHob)?;
}
hob.finish(&mem).map_err(Error::PopulateHob)?;
Ok(hob_offset)
}
#[cfg(feature = "tdx")]
fn init_tdx_memory(&mut self, sections: &[TdvfSection]) -> Result<()> {
fn init_tdx_memory(
&mut self,
sections: &[TdvfSection],
regions: &[TdVmmDataRegion],
) -> Result<()> {
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
let mem = guest_memory.memory();
@@ -1798,6 +1823,22 @@ impl Vm {
)
.map_err(Error::InitializeTdxMemoryRegion)?;
}
// The same way we let the hypervisor know about the TDVF sections, we
// must declare the VMM specific regions shared with the guest so that
// they won't be discarded.
for region in regions {
self.vm
.tdx_init_memory_region(
mem.get_host_address(GuestAddress(region.start_address))
.unwrap() as u64,
region.start_address,
region.length,
false,
)
.map_err(Error::InitializeTdxMemoryRegion)?;
}
Ok(())
}
@@ -1888,16 +1929,52 @@ impl Vm {
#[cfg(feature = "tdx")]
let sections = self.extract_tdvf_sections()?;
// Configuring the TDX regions requires that the vCPUs are created
#[cfg(feature = "acpi")]
let rsdp_addr = {
let mem = self.memory_manager.lock().unwrap().guest_memory().memory();
let rsdp_addr = crate::acpi::create_acpi_tables(
&mem,
&self.device_manager,
&self.cpu_manager,
&self.memory_manager,
&self.numa_nodes,
);
info!("Created ACPI tables: rsdp_addr = 0x{:x}", rsdp_addr.0);
rsdp_addr
};
#[cfg(all(feature = "tdx", not(feature = "acpi")))]
let vmm_data_regions: Vec<TdVmmDataRegion> = Vec::new();
// Create a VMM specific data region to share the ACPI tables with
// the guest. Reserving 64kiB to ensure the ACPI tables will fit.
#[cfg(all(feature = "tdx", feature = "acpi"))]
let vmm_data_regions = vec![TdVmmDataRegion {
start_address: rsdp_addr.0,
length: 0x10000,
region_type: TdVmmDataRegionType::AcpiTables,
}];
// Configuring the TDX regions requires that the vCPUs are created.
#[cfg(feature = "tdx")]
let hob_address = if self.config.lock().unwrap().tdx.is_some() {
self.populate_tdx_sections(&sections)?
// TDX sections are written to memory.
self.populate_tdx_sections(&sections, &vmm_data_regions)?
} else {
None
};
// Configure shared state based on loaded kernel
entry_point.map(|_| self.configure_system()).transpose()?;
entry_point
.map(|_| {
self.configure_system(
#[cfg(feature = "acpi")]
rsdp_addr,
)
})
.transpose()?;
#[cfg(feature = "tdx")]
if let Some(hob_address) = hob_address {
@@ -1908,7 +1985,10 @@ impl Vm {
.unwrap()
.initialize_tdx(hob_address)
.map_err(Error::CpuManager)?;
self.init_tdx_memory(&sections)?;
// Let the hypervisor know which memory ranges are shared with the
// guest. This prevents the guest from ignoring/discarding memory
// regions provided by the host.
self.init_tdx_memory(&sections, &vmm_data_regions)?;
// With TDX memory and CPU state configured TDX setup is complete
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
}
@@ -1928,53 +2008,6 @@ impl Vm {
Ok(())
}
pub fn handle_pty(&self, event: EpollDispatch) -> Result<()> {
// Could be a little dangerous, picks up a lock on device_manager
// and goes into a blocking read. If the epoll loops starts to be
// services by multiple threads likely need to revist this.
let dm = self.device_manager.lock().unwrap();
if matches!(event, EpollDispatch::SerialPty) {
if let Some(mut pty) = dm.serial_pty() {
let mut out = [0u8; 64];
let count = pty.main.read(&mut out).map_err(Error::PtyConsole)?;
let console = dm.console();
console
.queue_input_bytes_serial(&out[..count])
.map_err(Error::Console)?;
};
}
Ok(())
}
pub fn handle_stdin(&self) -> Result<()> {
let mut out = [0u8; 64];
let count = io::stdin()
.lock()
.read_raw(&mut out)
.map_err(Error::Console)?;
// Replace "\n" with "\r" to deal with Windows SAC (#1170)
if count == 1 && out[0] == 0x0a {
out[0] = 0x0d;
}
if matches!(
self.config.lock().unwrap().serial.mode,
ConsoleOutputMode::Tty
) {
self.device_manager
.lock()
.unwrap()
.console()
.queue_input_bytes_serial(&out[..count])
.map_err(Error::Console)?;
}
Ok(())
}
/// Gets a thread-safe reference counted pointer to the VM configuration.
pub fn get_config(&self) -> Arc<Mutex<VmConfig>> {
Arc::clone(&self.config)
@@ -2127,14 +2160,33 @@ impl Vm {
let mem = guest_memory.memory();
for range in ranges.regions() {
mem.read_exact_from(GuestAddress(range.gpa), fd, range.length as usize)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error transferring memory to socket: {}",
e
))
})?;
let mut offset: u64 = 0;
// Here we are manually handling the retry in case we can't the
// whole region at once because we can't use the implementation
// from vm-memory::GuestMemory of read_exact_from() as it is not
// following the correct behavior. For more info about this issue
// see: https://github.com/rust-vmm/vm-memory/issues/174
loop {
let bytes_read = mem
.read_from(
GuestAddress(range.gpa + offset),
fd,
(range.length - offset) as usize,
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error receiving memory from socket: {}",
e
))
})?;
offset += bytes_read as u64;
if offset == range.length {
break;
}
}
}
Ok(())
}
@@ -2150,30 +2202,41 @@ impl Vm {
let mem = guest_memory.memory();
for range in ranges.regions() {
mem.write_all_to(GuestAddress(range.gpa), fd, range.length as usize)
.map_err(|e| {
MigratableError::MigrateSend(anyhow!(
"Error transferring memory to socket: {}",
e
))
})?;
let mut offset: u64 = 0;
// Here we are manually handling the retry in case we can't the
// whole region at once because we can't use the implementation
// from vm-memory::GuestMemory of write_all_to() as it is not
// following the correct behavior. For more info about this issue
// see: https://github.com/rust-vmm/vm-memory/issues/174
loop {
let bytes_written = mem
.write_to(
GuestAddress(range.gpa + offset),
fd,
(range.length - offset) as usize,
)
.map_err(|e| {
MigratableError::MigrateSend(anyhow!(
"Error transferring memory to socket: {}",
e
))
})?;
offset += bytes_written as u64;
if offset == range.length {
break;
}
}
}
Ok(())
}
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
let mut table = MemoryRangeTable::default();
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
for region in guest_memory.memory().iter() {
table.push(MemoryRange {
gpa: region.start_addr().raw_value(),
length: region.len() as u64,
});
}
Ok(table)
self.memory_manager
.lock()
.unwrap()
.memory_range_table(false)
}
pub fn device_tree(&self) -> Arc<Mutex<DeviceTree>> {
@@ -2209,6 +2272,10 @@ impl Vm {
.notify_power_button()
.map_err(Error::PowerButton)
}
pub fn memory_manager_data(&self) -> MemoryManagerSnapshotData {
self.memory_manager.lock().unwrap().snapshot_data()
}
}
impl Pausable for Vm {
@@ -2312,11 +2379,7 @@ impl Snapshottable for Vm {
let common_cpuid = {
#[cfg(feature = "tdx")]
let tdx_enabled = self.config.lock().unwrap().tdx.is_some();
let phys_bits = physical_bits(
self.config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(self.config.lock().unwrap().cpus.max_phys_bits);
arch::generate_common_cpuid(
self.hypervisor.clone(),
None,
@@ -2621,7 +2684,7 @@ mod tests {
let gic = create_gic(&vm, 1).unwrap();
assert!(create_fdt(
&mem,
&CString::new("console=tty0").unwrap(),
"console=tty0",
vec![0],
Some((0, 0, 0)),
&dev_info,
@@ -2629,6 +2692,7 @@ mod tests {
&None,
&(0x1_0000_0000, 0x1_0000),
&BTreeMap::new(),
None,
)
.is_ok())
}
@@ -2638,7 +2702,7 @@ mod tests {
#[test]
pub fn test_vm() {
use hypervisor::VmExit;
use vm_memory::{GuestMemory, GuestMemoryRegion};
use vm_memory::{Address, GuestMemory, GuestMemoryRegion};
// This example based on https://lwn.net/Articles/658511/
let code = [
0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */