Compare commits

..

20 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Hao Xu <howeyxu@tencent.com>
2023-04-18 11:47:31 -07:00
100 changed files with 1511 additions and 2158 deletions

View File

@@ -7,10 +7,6 @@ on:
pull_request:
paths: resources/Dockerfile
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
main:
runs-on: ubuntu-latest
@@ -24,19 +20,19 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to ghcr
uses: docker/login-action@v2
- name: Login to DockerHub
if: ${{ github.event_name == 'push' }}
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# list of Docker images to use as base name for tags
images: cloudhypervisor/dev
# generate Docker tags based on the following events/attributes
tags: |
type=raw,value={{date 'YYYYMMDD'}}-0

View File

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

280
Cargo.lock generated
View File

@@ -5,9 +5,9 @@ version = 3
[[package]]
name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#98dcb0309d362dd83f6ffcac4f66914a2fbd5a73"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#12bb6d7b252831527e630f8b3ef48877dbb11924"
dependencies = [
"zerocopy",
"vm-memory",
]
[[package]]
@@ -36,9 +36,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.70"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "api_client"
@@ -179,7 +179,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloud-hypervisor"
version = "32.1.0"
version = "30.1.0"
dependencies = [
"anyhow",
"api_client",
@@ -224,9 +224,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]]
name = "darling"
version = "0.14.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
dependencies = [
"darling_core",
"darling_macro",
@@ -234,9 +234,9 @@ dependencies = [
[[package]]
name = "darling_core"
version = "0.14.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [
"fnv",
"ident_case",
@@ -248,9 +248,9 @@ dependencies = [
[[package]]
name = "darling_macro"
version = "0.14.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [
"darling_core",
"quote",
@@ -297,22 +297,22 @@ dependencies = [
[[package]]
name = "dirs"
version = "5.0.0"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.0"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
"windows-sys 0.45.0",
"winapi",
]
[[package]]
@@ -340,13 +340,13 @@ dependencies = [
[[package]]
name = "errno"
version = "0.3.1"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys 0.48.0",
"winapi",
]
[[package]]
@@ -382,9 +382,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "gdbstub"
version = "0.6.4"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4fddc6f9d12cbef29e395d9a6b48c128f513c8a2ded7048c97ed5c484e53e7"
checksum = "32c95766e0414f8bfc1d07055574c621b67739466d6ba516c4fef8e99d30d2e6"
dependencies = [
"bitflags",
"cfg-if",
@@ -487,20 +487,19 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.10"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.48.0",
"windows-sys 0.42.0",
]
[[package]]
name = "io-uring"
version = "0.5.13"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
checksum = "41c85eff7f7c8d3ab8c7ec87313c0c194bbaf4371bb7d40f80293ba01bce8264"
dependencies = [
"bitflags",
"libc",
@@ -517,21 +516,21 @@ dependencies = [
[[package]]
name = "is-terminal"
version = "0.4.7"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys 0.48.0",
"windows-sys 0.45.0",
]
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "kvm-bindings"
@@ -602,9 +601,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.3.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f508063cc7bb32987c71511216bd5a32be15bccb6a80b52df8b9d7f01fc3aa2"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
@@ -668,7 +667,7 @@ dependencies = [
[[package]]
name = "mshv-bindings"
version = "0.1.1"
source = "git+https://github.com/rust-vmm/mshv?branch=main#c1230f282c2836ba89ee112146bf638343424de8"
source = "git+https://github.com/rust-vmm/mshv?branch=main#0b2af251285385f8e39c2cd0fe8ffacab534932f"
dependencies = [
"libc",
"serde",
@@ -680,7 +679,7 @@ dependencies = [
[[package]]
name = "mshv-ioctls"
version = "0.1.1"
source = "git+https://github.com/rust-vmm/mshv?branch=main#c1230f282c2836ba89ee112146bf638343424de8"
source = "git+https://github.com/rust-vmm/mshv?branch=main#0b2af251285385f8e39c2cd0fe8ffacab534932f"
dependencies = [
"libc",
"mshv-bindings",
@@ -760,9 +759,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.83"
version = "0.9.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b"
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
dependencies = [
"autocfg",
"cc",
@@ -826,9 +825,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.12"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "pci"
@@ -965,9 +964,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.52"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@@ -1034,9 +1033,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.29"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remain"
@@ -1051,9 +1050,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.23"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustc-hash"
@@ -1072,9 +1071,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.3"
version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2"
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
"bitflags",
"errno",
@@ -1086,9 +1085,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "scopeguard"
@@ -1107,24 +1106,24 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.17"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.156"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.156"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -1133,9 +1132,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.96"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa",
"ryu",
@@ -1144,9 +1143,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "2.3.2"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "331bb8c3bf9b92457ab7abecf07078c13f7d270ba490103e84e8b014490cd0b0"
checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
dependencies = [
"serde",
"serde_with_macros",
@@ -1154,9 +1153,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "2.3.2"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859011bddcc11f289f07f467cc1fe01c7a941daa4d8f6c40d4d1c92eb6d9319c"
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [
"darling",
"proc-macro2",
@@ -1170,9 +1169,9 @@ version = "0.1.0"
[[package]]
name = "signal-hook"
version = "0.3.15"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
dependencies = [
"libc",
"signal-hook-registry",
@@ -1258,18 +1257,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.39"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.39"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1329,9 +1328,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "versionize"
version = "0.1.10"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
dependencies = [
"bincode",
"crc64",
@@ -1357,7 +1356,7 @@ dependencies = [
[[package]]
name = "vfio-bindings"
version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#ea8f710464a24690ce109e6b7dfaa623dc518304"
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
dependencies = [
"vmm-sys-util",
]
@@ -1365,7 +1364,7 @@ dependencies = [
[[package]]
name = "vfio-ioctls"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#ea8f710464a24690ce109e6b7dfaa623dc518304"
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -1383,7 +1382,7 @@ dependencies = [
[[package]]
name = "vfio_user"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#e75c9415d973769c5fd1d07716eb92d6e5be7c48"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#afbbd5722885e961ce12baea12efe01d52ce14b0"
dependencies = [
"bitflags",
"libc",
@@ -1524,9 +1523,9 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.7.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ba81e2bcc21c0d2fc5e6683e79367e26ad219197423a498df801d79d5ba77bd"
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
dependencies = [
"log",
"virtio-bindings 0.1.0",
@@ -1559,7 +1558,7 @@ dependencies = [
[[package]]
name = "vm-fdt"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ad21ede0ddb4cc97448eeb64c1dfc27803b9ec08"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927d19b50c85fcd5ce904a8c"
[[package]]
name = "vm-memory"
@@ -1640,7 +1639,6 @@ dependencies = [
"vm-migration",
"vm-virtio",
"vmm-sys-util",
"zerocopy",
]
[[package]]
@@ -1707,13 +1705,13 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
@@ -1722,131 +1720,65 @@ version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "zerocopy"

View File

@@ -1,6 +1,6 @@
[package]
name = "cloud-hypervisor"
version = "32.1.0"
version = "30.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
default-run = "cloud-hypervisor"
@@ -29,7 +29,7 @@ strip = false
debug = true
[dependencies]
anyhow = "1.0.70"
anyhow = "1.0.69"
api_client = { path = "api_client" }
argh = "0.1.9"
dhat = { version = "0.3.2", optional = true }
@@ -40,9 +40,9 @@ libc = "0.2.139"
log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = "0.3.0"
serde_json = "1.0.96"
signal-hook = "0.3.15"
thiserror = "1.0.39"
serde_json = "1.0.93"
signal-hook = "0.3.14"
thiserror = "1.0.38"
tpm = { path = "tpm"}
tracer = { path = "tracer" }
vmm = { path = "vmm" }
@@ -56,10 +56,10 @@ kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
[dev-dependencies]
dirs = "5.0.0"
dirs = "4.0.0"
net_util = { path = "net_util" }
once_cell = "1.17.1"
serde_json = "1.0.96"
serde_json = "1.0.93"
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"

92
Jenkinsfile vendored
View File

@@ -192,52 +192,52 @@ pipeline {
}
}
}
// stage('Worker build - Windows guest') {
// agent { node { label 'jammy' } }
// when {
// beforeAgent true
// expression {
// return runWorkers
// }
// }
// environment {
// AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
// }
// stages {
// stage('Checkout') {
// steps {
// checkout scm
// }
// }
// stage('Install azure-cli') {
// steps {
// installAzureCli('jammy', 'amd64')
// }
// }
// stage('Download assets') {
// steps {
// sh "mkdir ${env.HOME}/workloads"
// sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2022-amd64-2.raw" --name windows-server-2022-amd64-2.raw --connection-string "$AZURE_CONNECTION_STRING"'
// }
// }
// stage('Run Windows guest integration tests') {
// options {
// timeout(time: 1, unit: 'HOURS')
// }
// steps {
// sh 'scripts/dev_cli.sh tests --integration-windows'
// }
// }
// stage('Run Windows guest integration tests for musl') {
// options {
// timeout(time: 1, unit: 'HOURS')
// }
// steps {
// sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
// }
// }
// }
// }
stage('Worker build - Windows guest') {
agent { node { label 'jammy' } }
when {
beforeAgent true
expression {
return runWorkers
}
}
environment {
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install azure-cli') {
steps {
installAzureCli('jammy', 'amd64')
}
}
stage('Download assets') {
steps {
sh "mkdir ${env.HOME}/workloads"
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2022-amd64-2.raw" --name windows-server-2022-amd64-2.raw --connection-string "$AZURE_CONNECTION_STRING"'
}
}
stage('Run Windows guest integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-windows'
}
}
stage('Run Windows guest integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
}
}
}
}
stage('Worker build - Metrics') {
agent { node { label 'jammy-metrics' } }
when {

View File

@@ -113,7 +113,7 @@ Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
Binary builds of the firmware files are available for the latest release of
[Rust Hypervisor
[Rust Hyperivor
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest)
and [our edk2
repository](https://github.com/cloud-hypervisor/edk2/releases/latest)
@@ -124,7 +124,7 @@ may be required.
### Firmware Booting
Cloud Hypervisor supports booting disk images containing all needed components
to run cloud workloads, a.k.a. cloud images.
to run cloud workloads, a.k.a. cloud images.
The following sample commands will download an Ubuntu Cloud image, converting
it into a format that Cloud Hypervisor can use and a firmware to boot the image
@@ -178,7 +178,7 @@ To build the kernel:
```shell
# Clone the Cloud Hypervisor Linux branch
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.2 linux-cloud-hypervisor
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.1.6 linux-cloud-hypervisor
$ pushd linux-cloud-hypervisor
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
@@ -372,8 +372,8 @@ are all equal and welcome means of contribution. See the
## Slack
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI),
[join us on Slack](https://cloud-hypervisor.slack.com/), and [participate in our community activities](https://cloud-hypervisor.slack.com/archives/C04R5DUQVBN).
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI)
and [join us on Slack](https://cloud-hypervisor.slack.com/).
## Mailing list

View File

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

View File

@@ -260,86 +260,32 @@ fn create_memory_node(
fdt.end_node(memory_node)?;
}
} else {
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = {
let mut ram_regions = Vec::new();
let mut current_start = guest_mem
.iter()
.next()
.map(GuestMemoryRegion::start_addr)
.expect("GuestMemory must have one memory region at least")
.raw_value();
let mut current_end = current_start;
for (start, size) in guest_mem
.iter()
.map(|m| (m.start_addr().raw_value(), m.len()))
{
if current_end == start {
// This zone is continuous with the previous one.
current_end += size;
} else {
ram_regions.push((current_start, current_end));
current_start = start;
current_end = start + size;
}
}
ram_regions.push((current_start, current_end));
ram_regions
};
if ram_regions.len() > 2 {
panic!(
"There should be up to two non-continuous regions, devidided by the
gap at the end of 32bit address space."
);
}
// Create the memory node for memory region before the gap
{
let (first_region_start, first_region_end) = ram_regions
.first()
.expect("There should be at last one memory region");
let ram_start = super::layout::RAM_START.raw_value();
let mem_32bit_reserved_start = super::layout::MEM_32BIT_RESERVED_START.raw_value();
if !((first_region_start <= &ram_start)
&& (first_region_end > &ram_start)
&& (first_region_end <= &mem_32bit_reserved_start))
{
panic!(
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
);
}
let mem_size = first_region_end - ram_start;
let mem_reg_prop = [ram_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_start);
let last_addr = guest_mem.last_addr().raw_value();
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
// Case 1: all RAM is under the hole
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node = fdt.begin_node("memory")?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
} else {
// Case 2: RAM is split by the hole
// Region 1: RAM before the hole
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
- super::layout::RAM_START.raw_value();
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
}
// Create the memory map entry for memory region after the gap if any
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
let ram_64bit_start = super::layout::RAM_64BIT_START.raw_value();
if second_region_start != &ram_64bit_start {
panic!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
);
}
let mem_size = second_region_end - ram_64bit_start;
let mem_reg_prop = [ram_64bit_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
// Region 2: RAM after the hole
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
let memory_node_name =
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;

View File

@@ -19,9 +19,7 @@ use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
pub const _NSIG: i32 = 65;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
/// Errors thrown while configuring aarch64 system.
#[derive(Debug)]
@@ -83,8 +81,8 @@ pub fn configure_vcpu(
Ok(mpidr)
}
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
vec![
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
let mut regions = vec![
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
(
GuestAddress(0),
@@ -103,21 +101,39 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
layout::PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved,
),
// 1GiB ~ 4032 MiB: RAM before the gap
(
];
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
// RAM space
// Case1: guest memory fits before the gap
if size <= ram_32bit_space_size {
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
// Case2: guest memory extends beyond the gap
} else {
// Push memory before the gap
regions.push((
layout::RAM_START,
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize,
ram_32bit_space_size as usize,
RegionType::Ram,
),
// 4GiB ~ inf: RAM after the gap
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
// Add the 32-bit reserved memory hole as a reserved region
(
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_RESERVED_SIZE as usize,
RegionType::Reserved,
),
]
));
// Other memory is placed after 4GiB
regions.push((
layout::RAM_64BIT_START,
(size - ram_32bit_space_size) as usize,
RegionType::Ram,
));
}
// Add the 32-bit reserved memory hole as a reserved region
regions.push((
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_RESERVED_SIZE as usize,
RegionType::Reserved,
));
regions
}
/// Configures the system and should be called once per vm before starting vcpu threads.
@@ -199,12 +215,26 @@ mod tests {
use super::*;
#[test]
fn test_arch_memory_regions_dram() {
let regions = arch_memory_regions();
fn test_arch_memory_regions_dram_2gb() {
let regions = arch_memory_regions((1usize << 31) as u64); //2GB
assert_eq!(5, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!((1usize << 31), regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[4].2);
}
#[test]
fn test_arch_memory_regions_dram_4gb() {
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
assert_eq!(6, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!(ram_32bit_space_size, regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[5].2);
assert_eq!(RegionType::Ram, regions[4].2);
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
}
}

View File

@@ -1,17 +1,18 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
// AArch64 system register encoding:
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
//
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
// +----------+---+-----+-----+-----+-----+-----+----+
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
// +----------+---+-----+-----+-----+-----+-----+----+
//
// Notes:
// - L and Rt are reserved as implementation defined fields, ignored.
///
/// AArch64 system register encoding:
/// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
///
/// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
/// +----------+---+-----+-----+-----+-----+-----+----+
/// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
/// +----------+---+-----+-----+-----+-----+-----+----+
///
/// Notes:
/// - L and Rt are reserved as implementation defined fields, ignored.
///
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
const SYSREG_OP0_SHIFT: u32 = 19;
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;

View File

@@ -82,7 +82,7 @@ pub mod aarch64;
pub use aarch64::{
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
layout::IRQ_BASE, uefi, EntryPoint,
};
#[cfg(target_arch = "x86_64")]
@@ -92,7 +92,7 @@ pub mod x86_64;
pub use x86_64::{
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG,
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint,
};
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.

View File

@@ -53,8 +53,6 @@ const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
#[cfg(feature = "tdx")]
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
pub const _NSIG: i32 = 65;
#[derive(Debug, Copy, Clone)]
/// Specifies the entry point address where the guest must start
/// executing code, as well as which of the supported boot protocols
@@ -210,6 +208,7 @@ impl From<Error> for super::Error {
}
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone, Debug)]
pub enum CpuidReg {
EAX,
@@ -775,13 +774,6 @@ pub fn configure_vcpu(
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
// Set ApicId in cpuid for each vcpu
// SAFETY: get host cpuid when eax=1
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
cpu_ebx &= 0xffffff;
cpu_ebx |= (id as u32) << 24;
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
if !kvm_hyperv {
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
@@ -834,29 +826,47 @@ pub fn configure_vcpu(
/// These should be used to configure the GuestMemory structure for the platform.
/// For x86_64 all addresses are valid from the start of the kernel except a
/// carve out at the end of 32bit address space.
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
vec![
// 0 GiB ~ 3GiB: memory before the gap
(
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START
.checked_add(layout::MEM_32BIT_DEVICES_SIZE)
.expect("32-bit reserved region is too large");
let requested_memory_size = GuestAddress(size);
let mut regions = Vec::new();
// case1: guest memory fits before the gap
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
// case2: guest memory extends beyond the gap
} else {
// push memory before the gap
regions.push((
GuestAddress(0),
layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
RegionType::Ram,
),
// 4 GiB ~ inf: memory after the gap
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
// 3 GiB ~ 3712 MiB: 32-bit device memory hole
(
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_DEVICES_SIZE as usize,
RegionType::SubRegion,
),
// 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole
(
layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE),
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
RegionType::Reserved,
),
]
));
regions.push((
layout::RAM_64BIT_START,
requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize,
RegionType::Ram,
));
}
// Add the 32-bit device memory hole as a sub region.
regions.push((
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_DEVICES_SIZE as usize,
RegionType::SubRegion,
));
// Add the 32-bit reserved memory hole as a sub region.
regions.push((
reserved_memory_gap_start,
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
RegionType::Reserved,
));
regions
}
/// Configures the system and should be called once per vm before starting vcpu threads.
@@ -954,102 +964,30 @@ fn configure_pvh(
// Create the memory map entries.
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
// Merge continuous memory regions into one region.
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = {
let mut ram_regions = Vec::new();
let mut current_start = guest_mem
.iter()
.next()
.map(GuestMemoryRegion::start_addr)
.expect("GuestMemory must have one memory region at least")
.raw_value();
let mut current_end = current_start;
for (start, size) in guest_mem
.iter()
.map(|m| (m.start_addr().raw_value(), m.len()))
{
if current_end == start {
// This zone is continuous with the previous one.
current_end += size;
} else {
ram_regions.push((current_start, current_end));
current_start = start;
current_end = start + size;
}
}
ram_regions.push((current_start, current_end));
ram_regions
};
if ram_regions.len() > 2 {
error!(
"There should be up to two non-continuous regions, devidided by the
gap at the end of 32bit address space (e.g. between 3G and 4G)."
);
return Err(super::Error::MemmapTableSetup);
}
// Create the memory map entry for memory region before the gap
{
let (first_region_start, first_region_end) =
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
let high_ram_start = layout::HIGH_RAM_START.raw_value();
let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
if !((first_region_start <= &high_ram_start)
&& (first_region_end > &high_ram_start)
&& (first_region_end <= &mem_32bit_reserved_start))
{
error!(
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
);
return Err(super::Error::MemmapTableSetup);
}
info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
high_ram_start, first_region_end
);
let mem_end = guest_mem.last_addr();
if mem_end < layout::MEM_32BIT_RESERVED_START {
add_memmap_entry(
&mut memmap,
high_ram_start,
first_region_end - high_ram_start,
layout::HIGH_RAM_START.raw_value(),
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
E820_RAM,
);
}
// Create the memory map entry for memory region after the gap if any
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
if second_region_start != &ram_64bit_start {
error!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
);
return Err(super::Error::MemmapTableSetup);
}
info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
ram_64bit_start, second_region_end
);
} else {
add_memmap_entry(
&mut memmap,
ram_64bit_start,
second_region_end - ram_64bit_start,
layout::HIGH_RAM_START.raw_value(),
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
E820_RAM,
);
if mem_end > layout::RAM_64BIT_START {
add_memmap_entry(
&mut memmap,
layout::RAM_64BIT_START.raw_value(),
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
E820_RAM,
);
}
}
add_memmap_entry(
@@ -1285,8 +1223,16 @@ mod tests {
use super::*;
#[test]
fn regions_base_addr() {
let regions = arch_memory_regions();
fn regions_lt_4gb() {
let regions = arch_memory_regions(1 << 29);
assert_eq!(3, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(1usize << 29, regions[0].1);
}
#[test]
fn regions_gt_4gb() {
let regions = arch_memory_regions((1 << 32) + 0x8000);
assert_eq!(4, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(GuestAddress(1 << 32), regions[1].0);
@@ -1310,10 +1256,11 @@ mod tests {
assert!(config_err.is_err());
// Now assigning some memory that falls before the 32bit memory hole.
let arch_mem_regions = arch_memory_regions();
let mem_size = 128 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter()
.filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX)
.filter(|r| r.2 == RegionType::Ram)
.map(|r| (r.0, r.1))
.collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
@@ -1331,18 +1278,48 @@ mod tests {
)
.unwrap();
// Now assigning some memory that falls after the 32bit memory hole.
let arch_mem_regions = arch_memory_regions();
// Now assigning some memory that is equal to the start of the 32bit memory hole.
let mem_size = 3328 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter()
.filter(|r| r.2 == RegionType::Ram)
.map(|r| {
if r.1 == usize::MAX {
(r.0, 128 << 20)
} else {
(r.0, r.1)
}
})
.map(|r| (r.0, r.1))
.collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system(
&gm,
GuestAddress(0),
&None,
no_vcpus,
None,
None,
None,
None,
None,
)
.unwrap();
configure_system(
&gm,
GuestAddress(0),
&None,
no_vcpus,
None,
None,
None,
None,
None,
)
.unwrap();
// Now assigning some memory that falls after the 32bit memory hole.
let mem_size = 3330 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter()
.filter(|r| r.2 == RegionType::Ram)
.map(|r| (r.0, r.1))
.collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system(

View File

@@ -8,17 +8,17 @@ edition = "2021"
default = []
[dependencies]
io-uring = "0.5.13"
io-uring = "0.5.12"
libc = "0.2.139"
log = "0.4.17"
qcow = { path = "../qcow" }
smallvec = "1.10.0"
thiserror = "1.0.39"
versionize = "0.1.10"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0"

View File

@@ -17,8 +17,8 @@ fn main() {
}
// This println!() has a special behavior, as it will set the environment
// variable BUILD_VERSION, so that it can be reused from the binary.
// variable BUILT_VERSION, so that it can be reused from the binary.
// Particularly, this is used from src/main.rs to display the exact
// version.
println!("cargo:rustc-env=BUILD_VERSION={version}");
println!("cargo:rustc-env=BUILT_VERSION={version}");
}

View File

@@ -6,16 +6,16 @@ edition = "2021"
[dependencies]
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.70"
anyhow = "1.0.69"
arch = { path = "../arch" }
bitflags = "1.3.2"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.139"
log = "0.4.17"
thiserror = "1.0.39"
thiserror = "1.0.38"
tpm = { path = "../tpm" }
versionize = "0.1.10"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" }
vm-memory = "0.10.0"

View File

@@ -4,7 +4,7 @@
//
use super::AcpiNotificationFlags;
use acpi_tables::{aml, Aml, AmlSink};
use acpi_tables::{aml, aml::Aml};
use std::sync::{Arc, Barrier};
use std::time::Instant;
use vm_device::interrupt::InterruptSourceGroup;
@@ -103,11 +103,11 @@ impl BusDevice for AcpiGedDevice {
}
impl Aml for AcpiGedDevice {
fn to_aml_bytes(&self, sink: &mut dyn AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
aml::Device::new(
"_SB_.GEC_".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_UID".into(), &"Generic Event Controller"),
&aml::Name::new(
"_CRS".into(),
@@ -121,13 +121,12 @@ impl Aml for AcpiGedDevice {
&aml::OpRegion::new(
"GDST".into(),
aml::OpRegionSpace::SystemMemory,
&(self.address.0 as usize),
&GED_DEVICE_ACPI_SIZE,
self.address.0 as usize,
GED_DEVICE_ACPI_SIZE,
),
&aml::Field::new(
"GDST".into(),
aml::FieldAccessType::Byte,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::WriteAsZeroes,
vec![aml::FieldEntry::Named(*b"GDAT", 8)],
),
@@ -164,7 +163,7 @@ impl Aml for AcpiGedDevice {
),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
aml::Device::new(
"_SB_.GED_".into(),
vec![
@@ -188,7 +187,7 @@ impl Aml for AcpiGedDevice {
),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}

View File

@@ -78,40 +78,33 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
#### Virtual Machine (VM) Actions
| Action | Endpoint | Request Body | Response Body | Prerequisites |
| ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ |
| Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet |
| Delete the VM | `/vm.delete` | N/A | N/A | N/A |
| Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted |
| Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted |
| Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted |
| Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted |
| Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted |
| Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused |
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
| Perform a coredump of the VM* | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
* The `vmcoredump` action is available exclusively for the `x86_64`
architecture and can be executed only when the `guest_debug` feature is
enabled. Without this feature, the corresponding REST API endpoint is not
available.
| Action | Endpoint | Request Body | Response Body | Prerequisites |
| ---------------------------------- | --------------------- | --------------------------- | ------------------------ | -------------------------------- |
| Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet |
| Delete the VM | `/vm.delete` | N/A | N/A | N/A |
| Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted |
| Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted |
| Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted |
| Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted |
| Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted |
| Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused |
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
| Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
### REST API Examples
@@ -228,7 +221,7 @@ The CLI options are parsed by the
[internal API](#internal-api) commands.
The REST API is processed by an HTTP thread using the
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/micro-http)
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
crate. As with the CLI, the HTTP requests eventually get translated into
[internal API](#internal-api) commands.
@@ -386,5 +379,5 @@ APIs work together, let's look at a complete VM creation flow, from the
```
1. The Cloud Hypervisor HTTP thread sends the formed HTTP response back to the
user. This is abstracted by the
[micro_http](https://github.com/firecracker-microvm/micro-http)
[micro_http](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
crate.

View File

@@ -266,8 +266,11 @@ _Example_
### `file`
Path to the file backing the memory zone. The file will be opened and used as
the backing file for the `mmap(2)` operation.
Path to the file backing the memory zone. This can be either a file or a
directory. In case of a file, it will be opened and used as the backing file
for the `mmap(2)` operation. In case of a directory, a temporary file with no
hard link on the filesystem will be created. This file will be used as the
backing file for the `mmap(2)` operation.
This option can be particularly useful when trying to back a part of the guest
RAM with a well known file. In the context of the snapshot/restore feature, and

View File

@@ -6,5 +6,5 @@ edition = "2021"
[dependencies]
libc = "0.2.139"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"

159
fuzz/Cargo.lock generated
View File

@@ -5,16 +5,16 @@ version = 3
[[package]]
name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#98dcb0309d362dd83f6ffcac4f66914a2fbd5a73"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#4fd38dd5f746730ec5ae848dafcf8c2f50a13fc3"
dependencies = [
"zerocopy",
"vm-memory",
]
[[package]]
name = "anyhow"
version = "1.0.71"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "api_client"
@@ -25,9 +25,9 @@ dependencies = [
[[package]]
name = "arbitrary"
version = "1.3.0"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad"
[[package]]
name = "arc-swap"
@@ -76,7 +76,7 @@ dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
@@ -143,7 +143,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloud-hypervisor"
version = "31.0.0"
version = "29.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -208,9 +208,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]]
name = "darling"
version = "0.20.1"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
dependencies = [
"darling_core",
"darling_macro",
@@ -218,27 +218,27 @@ dependencies = [
[[package]]
name = "darling_core"
version = "0.20.1"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.15",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.1"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [
"darling_core",
"quote",
"syn 2.0.15",
"syn",
]
[[package]]
@@ -296,9 +296,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "getrandom"
version = "0.2.9"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
@@ -351,15 +351,15 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jobserver"
version = "0.1.26"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
@@ -393,9 +393,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libfuzzer-sys"
@@ -498,9 +498,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.57"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@@ -518,9 +518,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.27"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -536,13 +536,13 @@ dependencies = [
[[package]]
name = "remain"
version = "0.2.8"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c"
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
"syn",
]
[[package]]
@@ -556,9 +556,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "seccompiler"
@@ -571,35 +571,35 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.17"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.163"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.163"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.96"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa",
"ryu",
@@ -608,9 +608,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "2.3.3"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
dependencies = [
"serde",
"serde_with_macros",
@@ -618,14 +618,14 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "2.3.3"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.15",
"syn",
]
[[package]]
@@ -665,20 +665,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.109"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
dependencies = [
"proc-macro2",
"quote",
@@ -687,22 +676,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.40"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
"syn",
]
[[package]]
@@ -731,24 +720,24 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "uuid"
version = "1.3.3"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [
"getrandom",
]
[[package]]
name = "versionize"
version = "0.1.10"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
dependencies = [
"bincode",
"crc64",
@@ -756,7 +745,7 @@ dependencies = [
"quote",
"serde",
"serde_derive",
"syn 1.0.109",
"syn",
"versionize_derive",
"vmm-sys-util",
]
@@ -764,11 +753,11 @@ dependencies = [
[[package]]
name = "versionize_derive"
version = "0.1.4"
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6"
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
@@ -1000,7 +989,6 @@ dependencies = [
"vm-migration",
"vm-virtio",
"vmm-sys-util",
"zerocopy",
]
[[package]]
@@ -1042,24 +1030,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zerocopy"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]

View File

@@ -12,7 +12,7 @@ cargo-fuzz = true
block_util = { path = "../block_util" }
devices = { path = "../devices" }
epoll = "4.3.1"
libc = "0.2.144"
libc = "0.2.138"
libfuzzer-sys = "0.4.6"
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }

View File

@@ -6,22 +6,22 @@ edition = "2021"
license = "Apache-2.0 OR BSD-3-Clause"
[features]
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"]
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"]
kvm = ["kvm-ioctls", "kvm-bindings"]
mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = []
[dependencies]
anyhow = "1.0.70"
anyhow = "1.0.69"
byteorder = "1.4.3"
thiserror = "1.0.39"
thiserror = "1.0.38"
libc = "0.2.139"
log = "0.4.17"
kvm-ioctls = { version = "0.13.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_with = { version = "2.3.2", default-features = false, features = ["macros"] }
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }

View File

@@ -26,6 +26,7 @@ pub const MTRR_MEM_TYPE_WB: u64 = 0x6;
pub const NUM_IOAPIC_PINS: usize = 24;
// X86 Exceptions
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Debug)]
pub enum Exception {
DE = 0, // Divide Error

View File

@@ -133,7 +133,4 @@ pub trait Hypervisor: Send + Sync {
fn get_guest_debug_hw_bps(&self) -> usize {
unimplemented!()
}
/// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32;
}

View File

@@ -243,6 +243,7 @@ impl KvmGicV3Its {
}
/// Method to initialize the GIC device
#[allow(clippy::new_ret_no_self)]
pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
// This is inside KVM module
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");

View File

@@ -335,17 +335,16 @@ impl KvmVm {
}
}
///
/// Implementation of Vm trait for KVM
///
/// # Examples
///
/// ```
/// # use hypervisor::kvm::KvmHypervisor;
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// Example:
/// #[cfg(feature = "kvm")]
/// extern crate hypervisor
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
/// vm.set/get().unwrap()
///
impl vm::Vm for KvmVm {
#[cfg(target_arch = "x86_64")]
///
@@ -918,16 +917,13 @@ impl KvmHypervisor {
}
}
/// Implementation of Hypervisor trait for KVM
///
/// # Examples
///
/// ```
/// # use hypervisor::kvm::KvmHypervisor;
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// Example:
/// #[cfg(feature = "kvm")]
/// extern crate hypervisor
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
///
impl hypervisor::Hypervisor for KvmHypervisor {
///
/// Returns the type of the hypervisor
@@ -936,15 +932,13 @@ impl hypervisor::Hypervisor for KvmHypervisor {
HypervisorType::Kvm
}
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object
///
/// # Examples
///
/// ```
/// # use hypervisor::kvm::KvmHypervisor;
/// use hypervisor::kvm::KvmVm;
/// Example
/// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// use hypervisor::KvmVm;
/// let hypervisor = KvmHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm_with_type(0).unwrap();
/// ```
/// let vm = hypervisor.create_vm_with_type(KvmVmType::LegacyVm).unwrap()
///
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn vm::Vm>> {
let fd: VmFd;
loop {
@@ -998,15 +992,13 @@ impl hypervisor::Hypervisor for KvmHypervisor {
}
/// Create a KVM vm object and return the object as Vm trait object
///
/// # Examples
///
/// ```
/// # use hypervisor::kvm::KvmHypervisor;
/// use hypervisor::kvm::KvmVm;
/// Example
/// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// use hypervisor::KvmVm;
/// let hypervisor = KvmHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm().unwrap();
/// ```
/// let vm = hypervisor.create_vm().unwrap()
///
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
#[allow(unused_mut)]
let mut vm_type: u64 = 0; // Create with default platform type
@@ -1084,11 +1076,6 @@ impl hypervisor::Hypervisor for KvmHypervisor {
self.kvm.get_guest_debug_hw_bps() as usize
}
}
/// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32 {
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
}
}
/// Vcpu struct for KVM
pub struct KvmVcpu {
@@ -1100,17 +1087,15 @@ pub struct KvmVcpu {
hyperv_synic: AtomicBool,
}
/// Implementation of Vcpu trait for KVM
///
/// # Examples
///
/// ```
/// # use hypervisor::kvm::KvmHypervisor;
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// Example:
/// #[cfg(feature = "kvm")]
/// extern crate hypervisor
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// let vcpu = vm.create_vcpu(0, None).unwrap();
/// ```
/// vcpu.get/set().unwrap()
///
impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "x86_64")]
///
@@ -1812,10 +1797,11 @@ impl cpu::Vcpu for KvmVcpu {
/// # Example
///
/// ```rust
/// # use hypervisor::kvm::KvmHypervisor;
/// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hv = Arc::new(kvm);
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hv.create_vm().expect("new VM fd creation failed");
/// vm.enable_split_irq().unwrap();
/// let vcpu = vm.create_vcpu(0, None).unwrap();
@@ -1983,10 +1969,11 @@ impl cpu::Vcpu for KvmVcpu {
/// # Example
///
/// ```rust
/// # use hypervisor::kvm::KvmHypervisor;
/// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hv = Arc::new(kvm);
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hv.create_vm().expect("new VM fd creation failed");
/// vm.enable_split_irq().unwrap();
/// let vcpu = vm.create_vcpu(0, None).unwrap();

View File

@@ -48,9 +48,9 @@ mod cpu;
/// Device related module
mod device;
pub use crate::hypervisor::{Hypervisor, HypervisorError};
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
pub use device::HypervisorDeviceError;
pub use hypervisor::{Hypervisor, HypervisorError};
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::{aarch64, GicState};
use std::sync::Arc;

View File

@@ -195,16 +195,13 @@ impl MshvHypervisor {
}
}
/// Implementation of Hypervisor trait for Mshv
///
/// # Examples
///
/// ```
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// Example:
/// #[cfg(feature = "mshv")]
/// extern crate hypervisor
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
///
impl hypervisor::Hypervisor for MshvHypervisor {
///
/// Returns the type of the hypervisor
@@ -213,16 +210,13 @@ impl hypervisor::Hypervisor for MshvHypervisor {
HypervisorType::Mshv
}
/// Create a mshv vm object and return the object as Vm trait object
///
/// # Examples
///
/// ```
/// Example
/// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor;
/// use hypervisor::mshv::MshvVm;
/// # use hypervisor::MshvHypervisor;
/// use hypervisor::MshvVm;
/// let hypervisor = MshvHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm().unwrap();
/// ```
/// let vm = hypervisor.create_vm().unwrap()
///
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
let fd: VmFd;
loop {
@@ -279,13 +273,6 @@ impl hypervisor::Hypervisor for MshvHypervisor {
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
Ok(Vec::new())
}
/// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32 {
// TODO: Using HV_MAXIMUM_PROCESSORS would be better
// but the ioctl API is limited to u8
256
}
}
/// Vcpu struct for Microsoft Hypervisor
@@ -298,17 +285,15 @@ pub struct MshvVcpu {
}
/// Implementation of Vcpu trait for Microsoft Hypervisor
///
/// # Examples
///
/// ```
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// Example:
/// #[cfg(feature = "mshv")]
/// extern crate hypervisor
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// let vcpu = vm.create_vcpu(0, None).unwrap();
/// ```
/// let vcpu = vm.create_vcpu(0).unwrap();
/// vcpu.get/set().unwrap()
///
impl cpu::Vcpu for MshvVcpu {
#[cfg(target_arch = "x86_64")]
///
@@ -461,10 +446,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name_HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -510,10 +495,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name_HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -583,14 +568,8 @@ impl cpu::Vcpu for MshvVcpu {
///
/// X86 specific call to setup the CPUID registers.
///
fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect();
let mshv_cpuid = <CpuId>::from_entries(&cpuid)
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
self.fd
.register_intercept_result_cpuid(&mshv_cpuid)
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
fn set_cpuid2(&self, _cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
Ok(())
}
#[cfg(target_arch = "x86_64")]
///
@@ -938,17 +917,15 @@ impl MshvVm {
///
/// Implementation of Vm trait for Mshv
///
/// # Examples
///
/// ```
/// Example:
/// #[cfg(feature = "mshv")]
/// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// # use hypervisor::MshvHypervisor;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
/// vm.set/get().unwrap()
///
impl vm::Vm for MshvVm {
#[cfg(target_arch = "x86_64")]
///

View File

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

View File

@@ -11,12 +11,12 @@ libc = "0.2.139"
log = "0.4.17"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
serde = "1.0.156"
thiserror = "1.0.39"
versionize = "0.1.10"
serde = "1.0.151"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
virtio-bindings = "0.2.0"
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0"
@@ -25,4 +25,4 @@ vmm-sys-util = "0.11.0"
once_cell = "1.17.1"
pnet = "0.33.0"
pnet_datalink = "0.33.0"
serde_json = "1.0.96"
serde_json = "1.0.93"

View File

@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.70"
anyhow = "1.0.69"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
@@ -20,9 +20,9 @@ vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
vmm-sys-util = "0.11.0"
libc = "0.2.139"
log = "0.4.17"
serde = { version = "1.0.156", features = ["derive"] }
thiserror = "1.0.39"
versionize = "0.1.10"
serde = { version = "1.0.151", features = ["derive"] }
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }

View File

@@ -511,16 +511,6 @@ impl MsixCap {
self.pba & 0xffff_fff8
}
pub fn table_set_offset(&mut self, addr: u32) {
self.table &= 0x7;
self.table += addr;
}
pub fn pba_set_offset(&mut self, addr: u32) {
self.pba &= 0x7;
self.pba += addr;
}
pub fn table_bir(&self) -> u32 {
self.table & 0x7
}

View File

@@ -14,7 +14,6 @@ use crate::{
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError;
use libc::{sysconf, _SC_PAGESIZE};
use std::any::Any;
use std::collections::{BTreeMap, HashMap};
use std::io;
@@ -28,9 +27,6 @@ use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::{
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
};
use vm_allocator::page_size::{
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
};
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
@@ -502,29 +498,6 @@ impl VfioCommon {
Ok(vfio_common)
}
/// In case msix table offset is not page size aligned, we need do some fixup to achive it.
/// Becuse we don't want the MMIO RW region and trap region overlap each other.
fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
let msix = self.interrupt.msix.as_mut().unwrap();
let msix_cap = &mut msix.cap;
// Suppose table_bir equals to pba_bir here. Am I right?
let (table_offset, table_size) = msix_cap.table_range();
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
return region_size;
}
let (pba_offset, pba_size) = msix_cap.pba_range();
let msix_sz = align_page_size_up(table_size + pba_size);
// Expand region to hold RW and trap region which both page size aligned
let size = std::cmp::max(region_size * 2, msix_sz * 2);
// let table starts from the middle of the region
msix_cap.table_set_offset((size / 2) as u32);
msix_cap.pba_set_offset((size / 2 + pba_offset - table_offset) as u32);
size
}
pub(crate) fn allocate_bars(
&mut self,
allocator: &Arc<Mutex<SystemAllocator>>,
@@ -688,16 +661,9 @@ impl VfioCommon {
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
}
PciBarRegionType::Memory64BitRegion => {
// We need do some fixup to keep MMIO RW region and msix cap region page size
// aligned.
region_size = self.fixup_msix_region(bar_id, region_size);
// BAR allocation must be naturally aligned
mmio_allocator
.allocate(
restored_bar_addr,
region_size,
// SAFETY: FFI call. Trivially safe.
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
)
.allocate(restored_bar_addr, region_size, Some(region_size))
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
}
};
@@ -834,23 +800,6 @@ impl VfioCommon {
});
}
pub(crate) fn get_msix_cap_idx(&self) -> Option<usize> {
let mut cap_next = self
.vfio_wrapper
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
while cap_next != 0 {
let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX {
return Some(cap_next as usize);
} else {
cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
}
}
None
}
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
let mut cap_next = self
.vfio_wrapper
@@ -1205,15 +1154,6 @@ impl VfioCommon {
return self.configuration.read_reg(reg_idx);
}
if let Some(id) = self.get_msix_cap_idx() {
let msix = self.interrupt.msix.as_mut().unwrap();
if reg_idx * 4 == id + 4 {
return msix.cap.table;
} else if reg_idx * 4 == id + 8 {
return msix.cap.pba;
}
}
// Since we don't support passing multi-functions devices, we should
// mask the multi-function bit, bit 7 of the Header Type byte on the
// register 3.
@@ -1376,6 +1316,18 @@ impl VfioPciDevice {
self.iommu_attached
}
fn align_4k(address: u64) -> u64 {
(address + 0xfff) & 0xffff_ffff_ffff_f000
}
fn is_4k_aligned(address: u64) -> bool {
(address & 0xfff) == 0
}
fn is_4k_multiple(size: u64) -> bool {
(size & 0xfff) == 0
}
fn generate_sparse_areas(
caps: &[VfioRegionInfoCap],
region_index: u32,
@@ -1387,14 +1339,14 @@ impl VfioPciDevice {
match cap {
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
VfioRegionInfoCap::MsixMappable => {
if !is_4k_aligned(region_start) {
if !Self::is_4k_aligned(region_start) {
error!(
"Region start address 0x{:x} must be at least aligned on 4KiB",
region_start
);
return Err(VfioPciError::RegionAlignment);
}
if !is_4k_multiple(region_size) {
if !Self::is_4k_multiple(region_size) {
error!(
"Region size 0x{:x} must be at least a multiple of 4KiB",
region_size
@@ -1406,8 +1358,7 @@ impl VfioPciDevice {
// the MSI-X PBA table, we must calculate the subregions
// around them, leading to a list of sparse areas.
// We want to make sure we will still trap MMIO accesses
// to these MSI-X specific ranges. If these region don't align
// with pagesize, we can achive it by enlarging its range.
// to these MSI-X specific ranges.
//
// Using a BtreeMap as the list provided through the iterator is sorted
// by key. This ensures proper split of the whole region.
@@ -1415,14 +1366,10 @@ impl VfioPciDevice {
if let Some(msix) = vfio_msix {
if region_index == msix.cap.table_bir() {
let (offset, size) = msix.cap.table_range();
let offset = align_page_size_down(offset);
let size = align_page_size_up(size);
inter_ranges.insert(offset, size);
}
if region_index == msix.cap.pba_bir() {
let (offset, size) = msix.cap.pba_range();
let offset = align_page_size_down(offset);
let size = align_page_size_up(size);
inter_ranges.insert(offset, size);
}
}
@@ -1436,7 +1383,8 @@ impl VfioPciDevice {
size: range_offset - current_offset,
});
}
current_offset = align_page_size_down(range_offset + range_size);
current_offset = Self::align_4k(range_offset + range_size);
}
if region_size > current_offset {
@@ -1534,15 +1482,6 @@ impl VfioPciDevice {
return Err(VfioPciError::MmapArea);
}
if !is_page_size_aligned(area.size) || !is_page_size_aligned(area.offset) {
warn!(
"Could not mmap sparse area that is not page size aligned (offset = 0x{:x}, size = 0x{:x})",
area.offset,
area.size,
);
return Ok(());
}
let user_memory_region = UserMemoryRegion {
slot: (self.memory_slot)(),
start: region.start.0 + area.offset,

View File

@@ -7,9 +7,9 @@ build = "../build.rs"
[dependencies]
argh = "0.1.9"
dirs = "5.0.0"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
dirs = "4.0.0"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
test_infra = { path = "../test_infra" }
thiserror = "1.0.39"
thiserror = "1.0.38"
wait-timeout = "0.2.0"

View File

@@ -110,23 +110,18 @@ impl Default for MetricsReport {
#[derive(Default)]
pub struct PerformanceTestOverrides {
test_iterations: Option<u32>,
test_timeout: Option<u32>,
}
impl fmt::Display for PerformanceTestOverrides {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(test_iterations) = self.test_iterations {
write!(f, "test_iterations = {test_iterations}, ")?;
}
if let Some(test_timeout) = self.test_timeout {
write!(f, "test_timeout = {test_timeout}")?;
write!(f, "test_iterations = {test_iterations}")?;
}
Ok(())
}
}
#[derive(Clone)]
pub struct PerformanceTestControl {
test_timeout: u32,
test_iterations: u32,
@@ -193,14 +188,7 @@ impl PerformanceTest {
.test_iterations
.unwrap_or(self.control.test_iterations)
{
// update the timeout in control if passed explicitly and run testcase with it
if let Some(test_timeout) = overrides.test_timeout {
let mut control: PerformanceTestControl = self.control.clone();
control.test_timeout = test_timeout;
metrics.push((self.func_ptr)(&control));
} else {
metrics.push((self.func_ptr)(&self.control));
}
metrics.push((self.func_ptr)(&self.control));
}
let mean = (self.unit_adjuster)(mean(&metrics).unwrap());
@@ -219,9 +207,9 @@ impl PerformanceTest {
// Calculate the timeout for each test
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
pub fn calc_timeout(&self, test_iterations: &Option<u32>, test_timeout: &Option<u32>) -> u64 {
((test_timeout.unwrap_or(self.control.test_timeout) + 20)
* test_iterations.unwrap_or(self.control.test_iterations)) as u64
pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 {
((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations))
as u64
}
}
@@ -599,7 +587,6 @@ fn run_test_with_timeout(
) -> Result<PerformanceTestResult, Error> {
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
let test_iterations = overrides.test_iterations;
let test_timeout = overrides.test_timeout;
let overrides = overrides.clone();
thread::spawn(move || {
println!(
@@ -622,7 +609,7 @@ fn run_test_with_timeout(
});
// Todo: Need to cleanup/kill all hanging child processes
let test_timeout = test.calc_timeout(&test_iterations, &test_timeout);
let test_timeout = test.calc_timeout(&test_iterations);
receiver
.recv_timeout(Duration::from_secs(test_timeout))
.map_err(|_| {
@@ -658,10 +645,6 @@ struct Options {
/// override number of test iterations
iterations: Option<u32>,
#[argh(option, long = "timeout")]
/// override test timeout, Ex. --timeout 5
timeout: Option<u32>,
#[argh(switch, short = 'V', long = "version")]
/// print version information
version: bool,
@@ -671,7 +654,7 @@ fn main() {
let opts: Options = argh::from_env();
if opts.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}
@@ -700,7 +683,6 @@ fn main() {
let overrides = Arc::new(PerformanceTestOverrides {
test_iterations: opts.iterations,
test_timeout: opts.timeout,
});
for test in test_list.iter() {

View File

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

View File

@@ -1,25 +1,11 @@
- [v32.1](#v321)
- [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v31.1](#v311)
- [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v30.1](#v301)
- [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v28.2](#v282)
- [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -29,10 +15,10 @@
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Removals](#removals)
- [Deprecations](#deprecations)
- [Contributors](#contributors-3)
- [Contributors](#contributors-1)
- [v28.1](#v281)
- [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -40,9 +26,9 @@
- [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Removals](#removals-1)
- [Contributors](#contributors-4)
- [Contributors](#contributors-2)
- [v27.0](#v270)
- [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages)
@@ -51,41 +37,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-5)
- [Contributors](#contributors-3)
- [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via-platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Deprecations](#deprecations-2)
- [Removals](#removals-2)
- [Contributors](#contributors-6)
- [Contributors](#contributors-4)
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Removals](#removals-3)
- [Contributors](#contributors-7)
- [Contributors](#contributors-5)
- [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website)
- [Contributors](#contributors-8)
- [Contributors](#contributors-6)
- [v23.1](#v231)
- [v23.0](#v230)
- [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Deprecations](#deprecations-4)
- [Contributors](#contributors-9)
- [Contributors](#contributors-7)
- [v22.1](#v221)
- [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -96,13 +82,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [Notable Bug fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [v20.2](#v202)
- [v20.1](#v201)
- [v20.0](#v200)
@@ -111,8 +97,8 @@
- [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code)
- [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [Notable bug fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [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)
@@ -120,8 +106,8 @@
- [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-13)
- [Notable bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [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)
@@ -131,31 +117,31 @@
- [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-14)
- [Contributors](#contributors-14)
- [Notable bug fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [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-15)
- [Contributors](#contributors-15)
- [Notable bug fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-13)
- [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-16)
- [Notable bug fixes](#notable-bug-fixes-14)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-16)
- [Contributors](#contributors-14)
- [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting)
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [`--api-socket` supports file descriptor parameter](#-api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-5)
- [Contributors](#contributors-17)
- [Contributors](#contributors-15)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -165,7 +151,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-6)
- [Contributors](#contributors-18)
- [Contributors](#contributors-16)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -173,13 +159,13 @@
- [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-19)
- [Contributors](#contributors-17)
- [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-20)
- [Contributors](#contributors-18)
- [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)
@@ -189,17 +175,17 @@
- [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)
- [New `--balloon` Parameter Added](#new-balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-21)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-19)
- [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-18)
- [Contributors](#contributors-22)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-20)
- [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)
@@ -212,17 +198,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-19)
- [Contributors](#contributors-23)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-21)
- [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-20)
- [Notable Bug Fixes](#notable-bug-fixes-18)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-24)
- [Contributors](#contributors-22)
- [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)
@@ -232,14 +218,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-25)
- [Contributors](#contributors-23)
- [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-26)
- [Contributors](#contributors-24)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -247,7 +233,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-27)
- [Contributors](#contributors-25)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -256,7 +242,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-28)
- [Contributors](#contributors-26)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -283,63 +269,7 @@
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v32.1
This is a bug fix release. The following issues have been addressed:
* Report errors explicitly to users when VM failed to boot (#5453)
* Fix VFIO on platforms with non-4k page size (#5450, #5469)
* Fix TDX initialization (#5454)
* Ensure all guest memory regions are page-size aligned (#5496)
* Fix seccomp filter lists related to virtio-console, serial and pty
(#5506, #5524)
* Populate APIC ID properly (#5512)
* Ignore and warn TAP FDs in more situations (#5522)
# v32.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v32.0. The following user visible changes have been made:
### Increased PCI Segment Limit
The maximum number of PCI segments that can be used is now 96 (up from 16).
### API Changes
* The VmmPingResponse now includes the PID as well as the build details.
(#5348)
### Notable Bug Fixes
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
* Properly preserve and close valid FDs for TAP devices (#5373)
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
* Only touch the tty flags if it's being used (#5343)
* Fix seccomp filter lists for vhost-user devices (#5361)
* The number of vCPUs is capped at the hypervisor maximum (#5357)
* Fixes for TTY reset (#5414)
* CPU topology fixes on MSHV (#5325)
* Seccomp fixes for older distributions (#5397)
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Anatol Belski <anbelski@linux.microsoft.com>
* Bo Chen <chen.bo@intel.com>
* Hao Xu <howeyxu@tencent.com>
* Muminul Islam <muislam@microsoft.com>
* Omer Faruk Bayram <omer.faruk@sartura.hr>
* Rafael Mendonca <rafaelmendsr@gmail.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Smit Gardhariya <gardhariya.smit@gmail.com>
* Wei Liu <liuwe@microsoft.com>
# v31.1
# v30.1
This is a bug fix release. The following issues have been addressed:
@@ -348,72 +278,10 @@ This is a bug fix release. The following issues have been addressed:
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
* Only touch the tty flags if it's being used (#5343)
* Fix seccomp filter lists for vhost-user devices (#5361)
# v31.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v31.0. The following user visible changes have been made:
### Update to Latest `acpi_tables`
Adapted to the latest [acpi_tables](https://github.com/rust-vmm/acpi_tables).
There has been significant API changes in the crate.
### Update Reference Kernel to 6.2
Updated the recommended guest kernel version from 6.1.6 to 6.2.
### Improvements on Console `SIGWINCH` Handler
A separate thread had been created to capture the `SIGWINCH` signal and resize
the guest console. Now the thread is skipped if the console is not resizable.
Two completely different code paths existed for handling console resizing, one
for `tty` and the other for `pty`. That makes the understanding of the console
handling code unnecessarily complicated. Now the code paths are unified. Both
`tty` and `pty` are supported in single `SIGWINCH` handler. And the new handler
can works with kernel versions earlier than v5.5.
### Remove Directory Support from `MemoryZoneConfig::file`
Setting a directory to `MemoryZoneConfig::file` is no longer supported.
Before this change, user can set a directory to `file` of the `--memory-zone`
option. In that case, a temporary file will be created as the backing file for
the `mmap(2)` operation. This functionality has been unnecessary since we had
the native support for hugepages and allocating anonymous shared memory.
### Documentation Improvements
* Various improvements in API document
* Improvements in Doc comments
* Updated Slack channel information in README
### Notable Bug Fixes
* Fixed the offset setting while removing the entire mapping of `vhost-user` FS
client.
* Fixed the `ShutdownVmm` and `Shutdown` commands to call the correct API
endpoint.
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Bo Chen <chen.bo@intel.com>
* Daniel Farina <daniel@fdr.io>
* Dom <peng6662001@163.com>
* Hao Xu <howeyxu@tencent.com>
* Muminul Islam <muislam@microsoft.com>
* Omer Faruk Bayram <omer.faruk@sartura.hr>
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Smit Gardhariya <gardhariya.smit@gmail.com>
* Yang <ailin.yang@intel.com>
* Yong He <alexyonghe@tencent.com>
* Fix the offset setting while removing the entire mapping of
`vhost-user` FS client (#5235)
* Fix the `ShutdownVmm` and `Shutdown` commands to call the correct API
endpoint (#5322)
# v30.0

View File

@@ -1,12 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
#
# When changing this file don't forget to update the tag name in the
# .github/workflows/docker-image.yaml file if doing multiple per day
FROM ubuntu:20.04 as dev
ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.67.1"
ARG RUST_TOOLCHAIN="1.66.1"
ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"

View File

@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 6.2.0 Kernel Configuration
# Linux/arm64 6.1.6 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
CONFIG_CC_IS_GCC=y
@@ -55,6 +55,7 @@ CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_IRQ_IPI=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
@@ -202,7 +203,6 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
CONFIG_SYSCTL=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_EXPERT=y
@@ -227,7 +227,6 @@ CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_SELFTEST is not set
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_BASE_RELATIVE=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
@@ -250,7 +249,7 @@ CONFIG_PERF_EVENTS=y
# end of General setup
CONFIG_ARM64=y
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_ARM64_PAGE_SHIFT=12
@@ -350,7 +349,6 @@ CONFIG_ARM64_ERRATUM_2054223=y
CONFIG_ARM64_ERRATUM_2067961=y
CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_2457168=y
CONFIG_ARM64_ERRATUM_2645198=y
CONFIG_CAVIUM_ERRATUM_22375=y
CONFIG_CAVIUM_ERRATUM_23144=y
CONFIG_CAVIUM_ERRATUM_23154=y
@@ -378,7 +376,7 @@ CONFIG_ARM64_PA_BITS=48
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SCHED_MC=y
# CONFIG_SCHED_CLUSTER is not set
CONFIG_SCHED_CLUSTER is not set
CONFIG_SCHED_SMT=y
CONFIG_NR_CPUS=128
CONFIG_HOTPLUG_CPU=y
@@ -473,6 +471,7 @@ CONFIG_RANDOMIZE_BASE=y
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
CONFIG_STACKPROTECTOR_PER_TASK=y
CONFIG_ARCH_NR_GPIO=0
# end of Kernel Features
#
@@ -560,7 +559,6 @@ CONFIG_ACPI_GENERIC_GSI=y
CONFIG_ACPI_CCA_REQUIRED=y
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y
# CONFIG_ACPI_FPDT is not set
# CONFIG_ACPI_EC_DEBUGFS is not set
# CONFIG_ACPI_AC is not set
# CONFIG_ACPI_BATTERY is not set
@@ -593,10 +591,8 @@ CONFIG_HAVE_ACPI_APEI=y
# CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_IORT=y
CONFIG_ACPI_GTDT=y
CONFIG_ACPI_APMT=y
CONFIG_ACPI_PPTT=y
# CONFIG_ACPI_PCC is not set
# CONFIG_ACPI_FFH is not set
# CONFIG_PMIC_OPREGION is not set
CONFIG_ACPI_VIOT=y
# CONFIG_ACPI_PRMT is not set
@@ -605,9 +601,6 @@ CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP=y
CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_MMIO=y
CONFIG_HAVE_KVM_MSI=y
@@ -661,7 +654,6 @@ CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
@@ -726,7 +718,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling
CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_FUNCTION_ALIGNMENT=0
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@@ -893,8 +884,7 @@ CONFIG_ZSMALLOC_STAT=y
#
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB_DEPRECATED is not set
# CONFIG_SLUB_TINY is not set
# CONFIG_SLOB is not set
CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SLAB_FREELIST_RANDOM is not set
CONFIG_SLAB_FREELIST_HARDENED=y
@@ -961,7 +951,6 @@ CONFIG_ZONE_DMA32=y
CONFIG_ZONE_DEVICE=y
# CONFIG_DEVICE_PRIVATE is not set
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_USES_PG_ARCH_X=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PERCPU_STATS=y
# CONFIG_GUP_TEST is not set
@@ -1133,6 +1122,7 @@ CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
CONFIG_PCI_DEBUG=y
CONFIG_PCI_STUB=y
@@ -1282,6 +1272,7 @@ CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB=y
# CONFIG_EFI_ZBOOT is not set
CONFIG_EFI_ARMSTUB_DTB_LOADER=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set
@@ -1335,7 +1326,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
CONFIG_ZRAM_DEF_COMP="lzo-rle"
# CONFIG_ZRAM_WRITEBACK is not set
# CONFIG_ZRAM_MEMORY_TRACKING is not set
# CONFIG_ZRAM_MULTI_COMP is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_DRBD is not set
@@ -1586,7 +1576,6 @@ CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_LEGACY_TIOCSTI is not set
# CONFIG_LDISC_AUTOLOAD is not set
#
@@ -1662,6 +1651,8 @@ CONFIG_DEVMEM=y
CONFIG_DEVPORT=y
# CONFIG_TCG_TPM is not set
# CONFIG_XILLYBUS is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# end of Character devices
#
@@ -1750,7 +1741,6 @@ CONFIG_GPIO_PL061=y
# Virtual GPIO drivers
#
# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set
@@ -2168,10 +2158,9 @@ CONFIG_UIO_DMEM_GENIRQ=y
# CONFIG_UIO_PRUSS is not set
# CONFIG_UIO_MF624 is not set
CONFIG_VFIO=y
CONFIG_VFIO_CONTAINER=y
CONFIG_VFIO_IOMMU_TYPE1=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_VIRQFD=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_PCI_CORE=y
CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y
@@ -2270,7 +2259,6 @@ CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
CONFIG_IOMMU_DMA=y
# CONFIG_IOMMUFD is not set
# CONFIG_ARM_SMMU is not set
# CONFIG_ARM_SMMU_V3 is not set
CONFIG_VIRTIO_IOMMU=y
@@ -2407,7 +2395,6 @@ CONFIG_ARM_PMU_ACPI=y
# CONFIG_HISI_PMU is not set
# CONFIG_HISI_PCIE_PMU is not set
# CONFIG_HNS3_PMU is not set
# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set
# end of Performance monitor support
CONFIG_RAS=y
@@ -2583,10 +2570,8 @@ CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_FILE_CACHE=y
# CONFIG_SQUASHFS_FILE_DIRECT is not set
CONFIG_SQUASHFS_DECOMP_SINGLE=y
# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
# CONFIG_SQUASHFS_DECOMP_MULTI is not set
# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
# CONFIG_SQUASHFS_XATTR is not set
CONFIG_SQUASHFS_ZLIB=y
# CONFIG_SQUASHFS_LZ4 is not set
@@ -2725,6 +2710,7 @@ CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_USER is not set
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
# CONFIG_CRYPTO_PCRYPT is not set
@@ -2886,8 +2872,6 @@ CONFIG_CRYPTO_USER_API_RNG=y
# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
# CONFIG_CRYPTO_SM4_ARM64_CE_CCM is not set
# CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set
# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set
# end of Accelerated Cryptographic Algorithms for CPU (arm64)
@@ -2926,7 +2910,6 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
#
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
# CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
@@ -3062,8 +3045,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_COMPRESSED is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set
@@ -3224,7 +3206,7 @@ CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
@@ -3263,6 +3245,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set
@@ -3271,6 +3254,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_MAPLE_TREE is not set
# CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set

View File

@@ -1,18 +1,18 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 6.2.0 Kernel Configuration
# Linux/x86 6.1.6 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4)"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=110300
CONFIG_GCC_VERSION=120201
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=23800
CONFIG_AS_VERSION=23700
CONFIG_LD_IS_BFD=y
CONFIG_LD_VERSION=23800
CONFIG_LD_VERSION=23700
CONFIG_LLD_VERSION=0
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_CC_CAN_LINK=y
CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
CONFIG_CC_HAS_ASM_INLINE=y
@@ -70,6 +70,7 @@ CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
@@ -227,7 +228,6 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
CONFIG_SYSCTL=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
@@ -254,7 +254,6 @@ CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_SELFTEST is not set
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
CONFIG_KALLSYMS_BASE_RELATIVE=y
@@ -275,6 +274,7 @@ CONFIG_PERF_EVENTS=y
# end of Kernel Performance Events And Counters
# CONFIG_PROFILING is not set
# CONFIG_RUST is not set
# end of General setup
CONFIG_64BIT=y
@@ -294,6 +294,7 @@ CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_NR_GPIO=1024
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_AUDIT_ARCH=y
CONFIG_X86_64_SMP=y
@@ -421,10 +422,7 @@ CONFIG_X86_INTEL_TSX_MODE_OFF=y
# CONFIG_X86_SGX is not set
CONFIG_EFI=y
CONFIG_EFI_STUB=y
# CONFIG_EFI_HANDOVER_PROTOCOL is not set
# CONFIG_EFI_MIXED is not set
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
@@ -457,20 +455,11 @@ CONFIG_HAVE_LIVEPATCH=y
CONFIG_CC_HAS_SLS=y
CONFIG_CC_HAS_RETURN_THUNK=y
CONFIG_CC_HAS_ENTRY_PADDING=y
CONFIG_FUNCTION_PADDING_CFI=11
CONFIG_FUNCTION_PADDING_BYTES=16
CONFIG_CALL_PADDING=y
CONFIG_HAVE_CALL_THUNKS=y
CONFIG_CALL_THUNKS=y
CONFIG_PREFIX_SYMBOLS=y
CONFIG_SPECULATION_MITIGATIONS=y
CONFIG_PAGE_TABLE_ISOLATION=y
CONFIG_RETPOLINE=y
CONFIG_RETHUNK=y
CONFIG_CPU_UNRET_ENTRY=y
CONFIG_CALL_DEPTH_TRACKING=y
# CONFIG_CALL_THUNKS_DEBUG is not set
CONFIG_CPU_IBPB_ENTRY=y
CONFIG_CPU_IBRS_ENTRY=y
# CONFIG_SLS is not set
@@ -544,7 +533,6 @@ CONFIG_HAVE_ACPI_APEI_NMI=y
# CONFIG_ACPI_CONFIGFS is not set
# CONFIG_ACPI_PFRUT is not set
# CONFIG_ACPI_PCC is not set
# CONFIG_ACPI_FFH is not set
# CONFIG_PMIC_OPREGION is not set
CONFIG_ACPI_VIOT=y
# CONFIG_ACPI_PRMT is not set
@@ -640,7 +628,6 @@ CONFIG_KVM=y
# CONFIG_KVM_WERROR is not set
CONFIG_KVM_INTEL=y
# CONFIG_KVM_AMD is not set
CONFIG_KVM_SMM=y
# CONFIG_KVM_XEN is not set
CONFIG_AS_AVX512=y
CONFIG_AS_SHA1_NI=y
@@ -697,7 +684,6 @@ CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
@@ -779,9 +765,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling
CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FUNCTION_ALIGNMENT_16B=y
CONFIG_FUNCTION_ALIGNMENT=16
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@@ -899,8 +882,7 @@ CONFIG_ZSMALLOC_STAT=y
#
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB_DEPRECATED is not set
# CONFIG_SLUB_TINY is not set
# CONFIG_SLOB is not set
CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SLAB_FREELIST_RANDOM is not set
CONFIG_SLAB_FREELIST_HARDENED=y
@@ -975,6 +957,7 @@ CONFIG_SECRETMEM=y
CONFIG_USERFAULTFD=y
CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
CONFIG_PTE_MARKER=y
CONFIG_PTE_MARKER_UFFD_WP=y
# CONFIG_LRU_GEN is not set
@@ -1139,6 +1122,7 @@ CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
CONFIG_PCI_DEBUG=y
CONFIG_PCI_STUB=y
@@ -1267,8 +1251,11 @@ CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# EFI (Extensible Firmware Interface) Support
#
CONFIG_EFI_ESRT=y
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set
@@ -1309,7 +1296,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
CONFIG_ZRAM_DEF_COMP="lzo-rle"
# CONFIG_ZRAM_WRITEBACK is not set
# CONFIG_ZRAM_MEMORY_TRACKING is not set
# CONFIG_ZRAM_MULTI_COMP is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_DRBD is not set
@@ -1564,7 +1550,6 @@ CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_LEGACY_TIOCSTI is not set
# CONFIG_LDISC_AUTOLOAD is not set
#
@@ -1639,6 +1624,8 @@ CONFIG_HANGCHECK_TIMER=y
# CONFIG_TCG_TPM is not set
# CONFIG_TELCLOCK is not set
# CONFIG_XILLYBUS is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# end of Character devices
#
@@ -1687,7 +1674,6 @@ CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y
CONFIG_GPIO_IDIO_16=y
#
# Memory mapped GPIO drivers
@@ -1731,7 +1717,6 @@ CONFIG_GPIO_PCI_IDIO_16=y
# Virtual GPIO drivers
#
# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set
@@ -1799,7 +1784,6 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0
# CONFIG_MAX63XX_WATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set
# CONFIG_ADVANTECH_EC_WDT is not set
# CONFIG_ALIM1535_WDT is not set
# CONFIG_ALIM7101_WDT is not set
# CONFIG_EBC_C384_WDT is not set
@@ -2140,10 +2124,9 @@ CONFIG_UIO_DMEM_GENIRQ=y
# CONFIG_UIO_MF624 is not set
# CONFIG_UIO_HV_GENERIC is not set
CONFIG_VFIO=y
CONFIG_VFIO_CONTAINER=y
CONFIG_VFIO_IOMMU_TYPE1=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_VIRQFD=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_PCI_CORE=y
CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y
@@ -2219,7 +2202,6 @@ CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
CONFIG_IOMMU_DMA=y
# CONFIG_AMD_IOMMU is not set
# CONFIG_INTEL_IOMMU is not set
# CONFIG_IOMMUFD is not set
# CONFIG_IRQ_REMAP is not set
CONFIG_HYPERV_IOMMU=y
CONFIG_VIRTIO_IOMMU=y
@@ -2562,7 +2544,12 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
#
# Memory initialization
#
CONFIG_INIT_STACK_NONE=y
CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
# CONFIG_INIT_STACK_ALL_PATTERN is not set
CONFIG_INIT_STACK_ALL_ZERO=y
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
@@ -2598,6 +2585,7 @@ CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_USER is not set
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
# CONFIG_CRYPTO_PCRYPT is not set
@@ -2807,7 +2795,6 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
#
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
# CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
@@ -2895,7 +2882,6 @@ CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y
@@ -2936,8 +2922,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_COMPRESSED is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set
@@ -3113,7 +3098,6 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y
CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACING_SUPPORT=y
@@ -3173,6 +3157,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set
@@ -3181,6 +3166,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_MAPLE_TREE is not set
# CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set

View File

@@ -6,8 +6,8 @@
CLI_NAME="Cloud Hypervisor"
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
CTR_IMAGE_VERSION="20230316-0"
CTR_IMAGE_TAG="cloudhypervisor/dev"
CTR_IMAGE_VERSION="20230123-0"
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker"
@@ -172,11 +172,7 @@ process_volumes_args() {
cmd_help() {
echo ""
echo "Cloud Hypervisor $(basename "$0")"
echo "Usage: $(basename "$0") [flags] <command> [<command args>]"
echo ""
echo "Available flags":
echo ""
echo " --local Set the container image version being used to \"local\"."
echo "Usage: $(basename "$0") <command> [<command args>]"
echo ""
echo "Available commands:"
echo ""
@@ -539,7 +535,6 @@ cmd_tests() {
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
--env USER="root" \
--env CH_LIBC="${libc}" \
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
"$CTR_IMAGE" \
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
fi

View File

@@ -225,8 +225,8 @@ fi
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
export TARGET_CC="musl-gcc"
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
export TARGET_CC="musl-gcc"
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
fi
export RUST_BACKTRACE=1
@@ -240,9 +240,7 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Both test_vfio and ovs-dpdk rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`

View File

@@ -56,8 +56,26 @@ popd
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then
build_custom_linux
SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
@@ -71,9 +89,7 @@ fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# Test ovs-dpdk relies on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1

View File

@@ -45,7 +45,29 @@ if [ $? -ne 0 ]; then
fi
popd
build_custom_linux
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then
SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""

View File

@@ -42,8 +42,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""
TARGET_CC=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET

View File

@@ -12,7 +12,9 @@ FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
FW="$WORKLOADS_DIR/hypervisor-fw"
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
build_custom_linux
if [ ! -f "$VMLINUX_IMAGE" ]; then
build_custom_linux
fi
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
MNT_DIR="mount_image"
@@ -50,9 +52,7 @@ cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR
# test_vfio rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1

View File

@@ -24,8 +24,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""
TARGET_CC=""
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
export TARGET_CC="musl-gcc"
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
export TARGET_CC="musl-gcc"
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
fi
# Check if the images are present

View File

@@ -26,8 +26,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""
TARGET_CC=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
# Check if the images are present

View File

@@ -169,9 +169,7 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Both test_vfio, ovs-dpdk and vDPA tests rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
# Update max locked memory to 'unlimited' to avoid issues with vDPA

View File

@@ -95,9 +95,7 @@ fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# setup hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
if [ -n "$test_filter" ]; then
@@ -107,12 +105,7 @@ fi
# Ensure that git commands can be run in this directory (for metrics report)
git config --global --add safe.directory $PWD
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE`
if [ -z $RUST_BACKTRACE_VALUE ];then
export RUST_BACKTRACE=1
else
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
fi
export RUST_BACKTRACE=1
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
RES=$?

View File

@@ -22,4 +22,3 @@ fi
export RUST_BACKTRACE=1
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
cargo test --doc --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1

View File

@@ -46,7 +46,7 @@ build_custom_linux() {
ARCH=$(uname -m)
SRCDIR=$PWD
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
LINUX_CUSTOM_BRANCH="ch-6.2"
LINUX_CUSTOM_BRANCH="ch-6.1.6"
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"

View File

@@ -688,7 +688,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env();
if matches!(toplevel.command, SubCommandEnum::Version(_)) {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}

View File

@@ -8,7 +8,7 @@ extern crate event_monitor;
use argh::FromArgs;
use libc::EFD_NONBLOCK;
use log::{warn, LevelFilter};
use log::LevelFilter;
use option_parser::OptionParser;
use seccompiler::SeccompAction;
use signal_hook::consts::SIGSYS;
@@ -33,8 +33,6 @@ enum Error {
#[cfg(feature = "guest_debug")]
#[error("Failed to create Debug EventFd: {0}")]
CreateDebugEventFd(#[source] std::io::Error),
#[error("Failed to create exit EventFd: {0}")]
CreateExitEventFd(#[source] std::io::Error),
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
CreateHypervisor(#[source] hypervisor::HypervisorError),
#[error("Failed to start the VMM thread: {0}")]
@@ -92,9 +90,9 @@ impl log::Log for Logger {
let duration = now.duration_since(self.start);
if record.file().is_some() && record.line().is_some() {
write!(
writeln!(
*(*(self.output.lock().unwrap())),
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n",
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}",
duration,
std::thread::current().name().unwrap_or("anonymous"),
record.level(),
@@ -103,9 +101,9 @@ impl log::Log for Logger {
record.args()
)
} else {
write!(
writeln!(
*(*(self.output.lock().unwrap())),
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n",
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}",
duration,
std::thread::current().name().unwrap_or("anonymous"),
record.level(),
@@ -511,10 +509,8 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
#[cfg(feature = "guest_debug")]
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
let vmm_thread = vmm::start_vmm_thread(
vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
env!("CARGO_PKG_VERSION").to_string(),
&api_socket_path,
api_socket_fd,
api_evt.try_clone().unwrap(),
@@ -526,46 +522,33 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
debug_evt.try_clone().unwrap(),
#[cfg(feature = "guest_debug")]
vm_debug_evt.try_clone().unwrap(),
exit_evt.try_clone().unwrap(),
&seccomp_action,
hypervisor,
)
.map_err(Error::StartVmmThread)?;
let r: Result<(), Error> = (|| {
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
if payload_present {
let vm_params = toplevel.to_vm_params();
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
if payload_present {
let vm_params = toplevel.to_vm_params();
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
// Create and boot the VM based off the VM config we just built.
let sender = api_request_sender.clone();
vmm::api::vm_create(
api_evt.try_clone().unwrap(),
api_request_sender,
Arc::new(Mutex::new(vm_config)),
)
.map_err(Error::VmCreate)?;
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
} else if let Some(restore_params) = toplevel.restore {
vmm::api::vm_restore(
api_evt.try_clone().unwrap(),
api_request_sender,
Arc::new(
config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?,
),
)
.map_err(Error::VmRestore)?;
}
Ok(())
})();
if r.is_err() {
if let Err(e) = exit_evt.write(1) {
warn!("writing to exit EventFd: {e}");
}
// Create and boot the VM based off the VM config we just built.
let sender = api_request_sender.clone();
vmm::api::vm_create(
api_evt.try_clone().unwrap(),
api_request_sender,
Arc::new(Mutex::new(vm_config)),
)
.map_err(Error::VmCreate)?;
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
} else if let Some(restore_params) = toplevel.restore {
vmm::api::vm_restore(
api_evt.try_clone().unwrap(),
api_request_sender,
Arc::new(config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?),
)
.map_err(Error::VmRestore)?;
}
vmm_thread
@@ -573,7 +556,7 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
.map_err(Error::ThreadJoin)?
.map_err(Error::VmmThread)?;
r.map(|_| api_socket_path)
Ok(api_socket_path)
}
fn main() {
@@ -587,7 +570,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env();
if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}

View File

@@ -5,12 +5,12 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
dirs = "5.0.0"
dirs = "4.0.0"
epoll = "4.3.1"
libc = "0.2.139"
once_cell = "1.17.1"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
vmm-sys-util = "0.11.0"
wait-timeout = "0.2.0"

View File

@@ -868,6 +868,14 @@ impl Guest {
.map_err(Error::Parsing)
}
#[cfg(target_arch = "x86_64")]
pub fn get_initial_apicid(&self) -> Result<u32, Error> {
self.ssh_command("grep \"initial apicid\" /proc/cpuinfo | grep -o \"[0-9]*\"")?
.trim()
.parse()
.map_err(Error::Parsing)
}
pub fn get_total_memory(&self) -> Result<u32, Error> {
self.ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")?
.trim()
@@ -1344,7 +1352,6 @@ pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Resu
})
}
#[derive(Clone)]
pub enum FioOps {
Read,
RandomRead,

View File

@@ -10,8 +10,6 @@
extern crate test_infra;
use api_client::simple_api_command;
use api_client::simple_api_full_command;
use net_util::MacAddr;
use std::collections::HashMap;
use std::fs;
@@ -32,9 +30,6 @@ use test_infra::*;
use vmm_sys_util::{tempdir::TempDir, tempfile::TempFile};
use wait_timeout::ChildExt;
// Constant taken from the VMM crate.
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
#[cfg(target_arch = "x86_64")]
mod x86_64 {
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
@@ -257,6 +252,26 @@ fn prepare_swtpm_daemon(tmp_dir: &TempDir) -> (std::process::Command, String) {
(swtpm_command, swtpm_socket_path)
}
fn curl_command(api_socket: &str, method: &str, url: &str, http_body: Option<&str>) {
let mut curl_args: Vec<&str> = ["--unix-socket", api_socket, "-i", "-X", method, url].to_vec();
if let Some(body) = http_body {
curl_args.push("-H");
curl_args.push("Accept: application/json");
curl_args.push("-H");
curl_args.push("Content-Type: application/json");
curl_args.push("-d");
curl_args.push(body);
}
let status = Command::new("curl")
.args(curl_args)
.status()
.expect("Failed to launch curl command");
assert!(status.success());
}
fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args(["--api-socket", api_socket, command]);
@@ -1209,10 +1224,7 @@ fn _test_virtio_fs(
.default_net()
.args(["--api-socket", &api_socket]);
if pci_segment.is_some() {
guest_command.args([
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
guest_command.args(["--platform", "num_pci_segments=16"]);
}
let fs_params = format!(
@@ -1910,7 +1922,7 @@ fn enable_guest_watchdog(guest: &Guest, watchdog_sec: u32) {
}
mod common_parallel {
use std::{fs::OpenOptions, io::SeekFrom, os::unix::net::UnixStream};
use std::{fs::OpenOptions, io::SeekFrom};
use crate::*;
@@ -1948,6 +1960,7 @@ mod common_parallel {
guest.wait_vm_boot(Some(120)).unwrap();
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
@@ -2051,16 +2064,19 @@ mod common_parallel {
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_421() {
test_cpu_topology(4, 2, 1, false);
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_142() {
test_cpu_topology(1, 4, 2, false);
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_262() {
test_cpu_topology(2, 6, 2, false);
}
@@ -2232,7 +2248,7 @@ mod common_parallel {
"--memory-zone",
"id=mem0,size=1G,hotplug_size=2G",
"--memory-zone",
"id=mem1,size=1G,shared=on",
"id=mem1,size=1G,file=/dev/shm",
"--memory-zone",
"id=mem2,size=1G,host_numa_node=0,hotplug_size=2G",
])
@@ -2321,10 +2337,7 @@ mod common_parallel {
.args(["--memory", "size=512M"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.args([
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS},iommu_segments=[1]"),
])
.args(["--platform", "num_pci_segments=16,iommu_segments=[1]"])
.default_disks()
.capture_output()
.default_net();
@@ -2480,10 +2493,7 @@ mod common_parallel {
.args(["--memory", "size=512M"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.args([
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
])
.args(["--platform", "num_pci_segments=16"])
.args([
"--disk",
format!(
@@ -2510,15 +2520,15 @@ mod common_parallel {
let grep_cmd = "lspci | grep \"Host bridge\" | wc -l";
let r = std::panic::catch_unwind(|| {
// There should be MAX_NUM_PCI_SEGMENTS PCI host bridges in the guest.
// There should be 16 PCI host bridges in the guest.
assert_eq!(
guest
.ssh_command(grep_cmd)
.unwrap()
.trim()
.parse::<u16>()
.parse::<u32>()
.unwrap_or_default(),
MAX_NUM_PCI_SEGMENTS
16
);
// Check both if /dev/vdc exists and if the block size is 4M.
@@ -3734,7 +3744,7 @@ mod common_parallel {
// line (We tag the command line from cloud-hypervisor for that purpose).
// The third device is added to validate that hotplug works correctly since
// it is being added to the L2 VM through hotplugging mechanism.
// Also, we pass-through a virtio-blk device to the L2 VM to test the 32-bit
// Also, we pass-through a vitio-blk device to the L2 VM to test the 32-bit
// vfio device support
fn test_vfio() {
setup_vfio_network_interfaces();
@@ -4054,9 +4064,8 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(1, 0));
let mut socket = UnixStream::connect(&api_socket).unwrap();
// Verify API server is running
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
@@ -4109,9 +4118,8 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(1, 0));
let mut socket = UnixStream::connect(&api_socket).unwrap();
// Verify API server is running
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
@@ -4122,12 +4130,15 @@ mod common_parallel {
);
let r = std::panic::catch_unwind(|| {
// socket has to be created again inside catch_unwind block to avoid errors
let mut socket = UnixStream::connect(&api_socket).unwrap();
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
@@ -4144,10 +4155,15 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(20, 0));
// Then shut it down
simple_api_command(&mut socket, "PUT", "shutdown", None).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.shutdown",
None,
);
// Then boot it again
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
@@ -4180,9 +4196,8 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(1, 0));
let mut socket = UnixStream::connect(&api_socket).unwrap();
// Verify API server is running
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
@@ -4193,12 +4208,15 @@ mod common_parallel {
);
let r = std::panic::catch_unwind(|| {
// socket has to be created again inside catch_unwind block to avoid errors
let mut socket = UnixStream::connect(&api_socket).unwrap();
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
@@ -4215,12 +4233,22 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(20, 0));
// Then delete it
simple_api_command(&mut socket, "PUT", "delete", None).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.delete",
None,
);
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it again
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
@@ -4254,9 +4282,8 @@ mod common_parallel {
thread::sleep(std::time::Duration::new(1, 0));
let mut socket = UnixStream::connect(&api_socket).unwrap();
// Verify API server is running
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
@@ -4265,12 +4292,15 @@ mod common_parallel {
direct_kernel_boot_path().to_str().unwrap(),
DIRECT_KERNEL_BOOT_CMDLINE,
);
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
thread::sleep(std::time::Duration::new(20, 0));
let r = std::panic::catch_unwind(|| {
@@ -5207,7 +5237,6 @@ mod common_parallel {
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_balloon_free_page_reporting() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
@@ -5307,10 +5336,7 @@ mod common_parallel {
.capture_output();
if pci_segment.is_some() {
cmd.args([
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
cmd.args(["--platform", "num_pci_segments=16"]);
}
let mut child = cmd.spawn().unwrap();
@@ -5446,10 +5472,7 @@ mod common_parallel {
.capture_output();
if pci_segment.is_some() {
cmd.args([
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
cmd.args(["--platform", "num_pci_segments=16"]);
}
let mut child = cmd.spawn().unwrap();
@@ -6277,13 +6300,11 @@ mod common_parallel {
}
#[test]
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
fn test_macvtap() {
_test_macvtap(false, "guestmacvtap0", "hostmacvtap0")
}
#[test]
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
fn test_macvtap_hotplug() {
_test_macvtap(true, "guestmacvtap1", "hostmacvtap1")
}

View File

@@ -309,7 +309,11 @@ impl Emulator {
}
self.established_flag_cached = true;
self.established_flag = est.resp.bit == 0;
if est.resp.bit != 0 {
self.established_flag = false;
} else {
self.established_flag = true;
}
self.established_flag
}

View File

@@ -8,8 +8,8 @@ edition = "2021"
libc = "0.2.139"
log = "0.4.17"
once_cell = "1.17.1"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
[features]
tracing = []

View File

@@ -11,5 +11,5 @@ crc32c = "0.6.3"
libc = "0.2.139"
log = "0.4.17"
remain = "0.2.6"
thiserror = "1.0.39"
thiserror = "1.0.38"
uuid = { version = "1.3.0", features = ["v4"] }

View File

@@ -145,7 +145,11 @@ impl DiskSpec {
let bits = f
.read_u32::<LittleEndian>()
.map_err(VhdxMetadataError::ReadMetadata)?;
disk_spec.has_parent = bits & BLOCK_HAS_PARENT != 0;
if bits & BLOCK_HAS_PARENT != 0 {
disk_spec.has_parent = true;
} else {
disk_spec.has_parent = false;
}
metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
} else if metadata_entry.item_id

View File

@@ -17,7 +17,7 @@ qcow = { path = "../qcow" }
vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
vhost-user-backend = "0.8.0"
virtio-bindings = "0.2.0"
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-memory = "0.10.0"
vmm-sys-util = "0.11.0"

View File

@@ -32,7 +32,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env();
if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}

View File

@@ -28,7 +28,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env();
if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}

View File

@@ -8,13 +8,13 @@ edition = "2021"
default = []
[dependencies]
anyhow = "1.0.70"
anyhow = "1.0.69"
arc-swap = "1.5.1"
block_util = { path = "../block_util" }
byteorder = "1.4.3"
epoll = "4.3.1"
event_monitor = { path = "../event_monitor" }
io-uring = "0.5.13"
io-uring = "0.5.12"
libc = "0.2.139"
log = "0.4.17"
net_gen = { path = "../net_gen" }
@@ -22,15 +22,15 @@ net_util = { path = "../net_util" }
pci = { path = "../pci" }
rate_limiter = { path = "../rate_limiter" }
seccompiler = "0.3.0"
serde = { version = "1.0.156", features = ["derive"] }
serde_json = "1.0.96"
serde = { version = "1.0.151", features = ["derive"] }
serde_json = "1.0.93"
serial_buffer = { path = "../serial_buffer" }
thiserror = "1.0.39"
versionize = "0.1.10"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vhost = { version = "0.6.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -39,24 +39,19 @@ pub mod vhost_user;
pub mod vsock;
pub mod watchdog;
pub use self::balloon::Balloon;
pub use self::block::{Block, BlockState};
pub use self::console::{Console, ConsoleResizer, Endpoint};
pub use self::device::{
DmaRemapping, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioInterrupt,
VirtioInterruptType, VirtioSharedMemoryList,
};
pub use self::epoll_helper::{
EpollHelper, EpollHelperError, EpollHelperHandler, EPOLL_HELPER_EVENT_LAST,
};
pub use self::iommu::{AccessPlatformMapping, Iommu, IommuMapping};
pub use self::mem::{BlocksState, Mem, VirtioMemMappingSource, VIRTIO_MEM_ALIGN_SIZE};
pub use self::net::{Net, NetCtrlEpollHandler};
pub use self::pmem::Pmem;
pub use self::rng::Rng;
pub use self::vdpa::{Vdpa, VdpaDmaMapping};
pub use self::vsock::Vsock;
pub use self::watchdog::Watchdog;
pub use self::balloon::*;
pub use self::block::*;
pub use self::console::*;
pub use self::device::*;
pub use self::epoll_helper::*;
pub use self::iommu::*;
pub use self::mem::*;
pub use self::net::*;
pub use self::pmem::*;
pub use self::rng::*;
pub use self::vdpa::*;
pub use self::vsock::*;
pub use self::watchdog::*;
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory};
use vm_virtio::VirtioDeviceType;
@@ -91,8 +86,8 @@ pub enum ActivateError {
ThreadSpawn(std::io::Error),
#[error("Failed to setup vhost-user-fs daemon: {0}")]
VhostUserFsSetup(vhost_user::Error),
#[error("Failed to setup vhost-user daemon: {0}")]
VhostUserSetup(vhost_user::Error),
#[error("Failed to setup vhost-user-blk daemon: {0}")]
VhostUserBlkSetup(vhost_user::Error),
#[error("Failed to create seccomp filter: {0}")]
CreateSeccompFilter(seccompiler::Error),
#[error("Failed to create rate limiter: {0}")]

View File

@@ -259,7 +259,6 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_mremap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_read, vec![]),

View File

@@ -605,7 +605,7 @@ impl VirtioDevice for Fs {
&mut self,
shm_regions: VirtioSharedMemoryList,
) -> std::result::Result<(), crate::Error> {
if let Some(cache) = self.cache.as_mut() {
if let Some(mut cache) = self.cache.as_mut() {
cache.0 = shm_regions;
Ok(())
} else {

View File

@@ -237,7 +237,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
.map_err(|e| {
EpollHelperError::IoError(std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed reconnecting vhost-user backend: {e:?}"),
format!("failed reconnecting vhost-user backend{e:?}"),
))
})?;
@@ -340,7 +340,7 @@ impl VhostUserCommon {
&slave_req_handler,
inflight.as_mut(),
)
.map_err(ActivateError::VhostUserSetup)?;
.map_err(ActivateError::VhostUserBlkSetup)?;
Ok(VhostUserEpollHandler {
vu: vu.clone(),
@@ -413,7 +413,7 @@ impl VhostUserCommon {
pub fn pause(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vu) = &self.vu {
vu.lock().unwrap().pause_vhost_user().map_err(|e| {
MigratableError::Pause(anyhow!("Error pausing vhost-user backend: {:?}", e))
MigratableError::Pause(anyhow!("Error pausing vhost-user-blk backend: {:?}", e))
})
} else {
Ok(())
@@ -423,7 +423,7 @@ impl VhostUserCommon {
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vu) = &self.vu {
vu.lock().unwrap().resume_vhost_user().map_err(|e| {
MigratableError::Resume(anyhow!("Error resuming vhost-user backend: {:?}", e))
MigratableError::Resume(anyhow!("Error resuming vhost-user-blk backend: {:?}", e))
})
} else {
Ok(())

View File

@@ -1,28 +1,28 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
//! The main job of `VsockConnection` is to forward data traffic, back and forth, between a
//! guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while
//! also managing its internal state.
//! To that end, `VsockConnection` implements:
//! - `VsockChannel` for:
//! - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and
//! - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and
//! - updating its internal state, by absorbing control packets (anything other than
//! VSOCK_OP_RW).
//! - `VsockEpollListener` for getting notified about the availability of data or free buffer
//! space at the host stream.
//!
//! Note: there is a certain asymmetry to the RX and TX data flows:
//! - RX transfers do not need any data buffering, since data is read straight from the
//! host stream and into the guest-provided RX buffer;
//! - TX transfers may require some data to be buffered by `VsockConnection`, if the host
//! peer can't keep up with reading the data that we're writing. This is because, once
//! the guest driver provides some data in a virtio TX buffer, the vsock device must
//! consume it. If that data can't be forwarded straight to the host stream, we'll
//! have to store it in a buffer (and flush it at a later time). Vsock flow control
//! ensures that our TX buffer doesn't overflow.
//
/// The main job of `VsockConnection` is to forward data traffic, back and forth, between a
/// guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while
/// also managing its internal state.
/// To that end, `VsockConnection` implements:
/// - `VsockChannel` for:
/// - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and
/// - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and
/// - updating its internal state, by absorbing control packets (anything other than
/// VSOCK_OP_RW).
/// - `VsockEpollListener` for getting notified about the availability of data or free buffer
/// space at the host stream.
///
/// Note: there is a certain asymmetry to the RX and TX data flows:
/// - RX transfers do not need any data buffering, since data is read straight from the
/// host stream and into the guest-provided RX buffer;
/// - TX transfers may require some data to be buffered by `VsockConnection`, if the host
/// peer can't keep up with reading the data that we're writing. This is because, once
/// the guest driver provides some data in a virtio TX buffer, the vsock device must
/// consume it. If that data can't be forwarded straight to the host stream, we'll
/// have to store it in a buffer (and flush it at a later time). Vsock flow control
/// ensures that our TX buffer doesn't overflow.
///
// The code in this file is best read with a fresh memory of the vsock protocol inner-workings.
// To help with that, here is a
//

View File

@@ -1,9 +1,9 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
//! This module implements our vsock connection state machine. The heavy lifting is done by
//! `connection::VsockConnection`, while this file only defines some constants and helper structs.
/// This module implements our vsock connection state machine. The heavy lifting is done by
/// `connection::VsockConnection`, while this file only defines some constants and helper structs.
///
mod connection;
mod txbuf;

View File

@@ -2,19 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
//
//! `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues.
//! There are two components to a vsock packet, each using its own descriptor in a
//! virtio queue:
//! - the packet header; and
//! - the packet data/buffer.
//! There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds
//! the header, and an optional second descriptor holds the data. The second descriptor is only
//! present for data packets (VSOCK_OP_RW).
//!
//! `VsockPacket` wraps these two buffers and provides direct access to the data stored
//! in guest memory. This is done to avoid unnecessarily copying data from guest memory
//! to temporary buffers, before passing it on to the vsock backend.
/// `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues.
/// There are two components to a vsock packet, each using its own descriptor in a
/// virtio queue:
/// - the packet header; and
/// - the packet data/buffer.
/// There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds
/// the header, and an optional second descriptor holds the data. The second descriptor is only
/// present for data packets (VSOCK_OP_RW).
///
/// `VsockPacket` wraps these two buffers and provides direct access to the data stored
/// in guest memory. This is done to avoid unnecessarily copying data from guest memory
/// to temporary buffers, before passing it on to the vsock backend.
///
use byteorder::{ByteOrder, LittleEndian};
use std::ops::Deref;
use std::sync::Arc;
@@ -436,6 +436,7 @@ mod tests {
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn test_tx_packet_assembly() {
// Test case: successful TX packet assembly.
{
@@ -580,6 +581,7 @@ mod tests {
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn test_packet_hdr_accessors() {
const SRC_CID: u64 = 1;
const DST_CID: u64 = 2;

View File

@@ -2,13 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
//
//! This module implements the Unix Domain Sockets backend for vsock - a mediator between
//! guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by
//! `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for
//! handling vsock connection states.
//!
//! Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend.
/// This module implements the Unix Domain Sockets backend for vsock - a mediator between
/// guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by
/// `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for
/// handling vsock connection states.
/// Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend.
///
mod muxer;
mod muxer_killq;
mod muxer_rxq;

View File

@@ -2,42 +2,35 @@
// SPDX-License-Identifier: Apache-2.0
//
//! `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e.
//! by implementing the `VsockBackend` trait, it abstracts away the gory details of translating
//! between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock
//! device model.
//!
//! The vsock muxer has two main roles:
//!
//! ## Vsock connection multiplexer
//!
//! It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The
//! muxer also routes packets to their owning connections. It does so via a connection
//! `HashMap`, keyed by what is basically a (host_port, guest_port) tuple.
//!
//! Vsock packet traffic needs to be inspected, in order to detect connection request
//! packets (leading to the creation of a new connection), and connection reset packets
//! (leading to the termination of an existing connection). All other packets, though, must
//! belong to an existing connection and, as such, the muxer simply forwards them.
//!
//! ## Event dispatcher
//!
//! There are three event categories that the vsock backend is interested it:
//! 1. A new host-initiated connection is ready to be accepted from the listening host Unix
//! socket;
//! 2. Data is available for reading from a newly-accepted host-initiated connection (i.e.
//! the host is ready to issue a vsock connection request, informing us of the
//! destination port to which it wants to connect);
//! 3. Some event was triggered for a connected Unix socket, that belongs to a
//! `VsockConnection`.
//!
//! The muxer gets notified about all of these events, because, as a `VsockEpollListener`
//! implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
//! other pollable FDs are then registered under this nested epoll FD.
//!
//! To route all these events to their handlers, the muxer uses another `HashMap` object,
//! mapping `RawFd`s to `EpollListener`s.
/// `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e.
/// by implementing the `VsockBackend` trait, it abstracts away the gory details of translating
/// between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock
/// device model.
///
/// The vsock muxer has two main roles:
/// 1. Vsock connection multiplexer:
/// It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The
/// muxer also routes packets to their owning connections. It does so via a connection
/// `HashMap`, keyed by what is basically a (host_port, guest_port) tuple.
/// Vsock packet traffic needs to be inspected, in order to detect connection request
/// packets (leading to the creation of a new connection), and connection reset packets
/// (leading to the termination of an existing connection). All other packets, though, must
/// belong to an existing connection and, as such, the muxer simply forwards them.
/// 2. Event dispatcher
/// There are three event categories that the vsock backend is interested it:
/// 1. A new host-initiated connection is ready to be accepted from the listening host Unix
/// socket;
/// 2. Data is available for reading from a newly-accepted host-initiated connection (i.e.
/// the host is ready to issue a vsock connection request, informing us of the
/// destination port to which it wants to connect);
/// 3. Some event was triggered for a connected Unix socket, that belongs to a
/// `VsockConnection`.
/// The muxer gets notified about all of these events, because, as a `VsockEpollListener`
/// implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
/// other pollable FDs are then registered under this nested epoll FD.
/// To route all these events to their handlers, the muxer uses another `HashMap` object,
/// mapping `RawFd`s to `EpollListener`s.
///
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{self, Read};
@@ -87,7 +80,7 @@ enum EpollListener {
},
/// A listener interested in new host-initiated connections.
HostSock,
/// A listener interested in reading host "connect \<port>" commands from a freshly
/// A listener interested in reading host "connect <port>" commands from a freshly
/// connected host socket.
LocalStream(UnixStream),
}
@@ -113,7 +106,7 @@ pub struct VsockMuxer {
/// The Unix socket, through which host-initiated connections are accepted.
host_sock: UnixListener,
/// The file system path of the host-side Unix socket. This is used to figure out the path
/// to Unix sockets listening on specific ports. I.e. "\<this path>_\<port number>".
/// to Unix sockets listening on specific ports. I.e. "<this path>_<port number>".
host_sock_path: String,
/// The nested epoll File, used to register epoll listeners.
epoll_file: File,

View File

@@ -2,29 +2,29 @@
// SPDX-License-Identifier: Apache-2.0
//
//! `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced
//! connection termination. I.e. after one peer issues a clean shutdown request
//! (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in
//! the near future (herein implemented via an expiring timer).
//!
//! Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather
//! an identifier - the connection key) to this queue. A subsequent pop() operation will
//! succeed if and only if the first connection in the queue is ready to be terminated (i.e.
//! its kill timer expired).
//!
//! Without using this queue, the muxer would have to walk its entire connection pool
//! (hashmap), whenever it needs to check for expired kill timers. With this queue, both
//! scheduling and termination are performed in constant time. However, since we don't want to
//! waste space on a kill queue that's as big as the connection hashmap itself, it is possible
//! that this queue may become full at times. We call this kill queue "synchronized" if we are
//! certain that all connections that are awaiting termination are present in the queue. This
//! means a simple constant-time pop() operation is enough to check whether any connections
//! need to be terminated. When the kill queue becomes full, though, pushing fails, so
//! connections that should be terminated are left out. The queue is not synchronized anymore.
//! When that happens, the muxer will first drain the queue, and then replace it with a new
//! queue, created by walking the connection pool, looking for connections that will be
//! expiring in the future.
/// `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced
/// connection termination. I.e. after one peer issues a clean shutdown request
/// (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in
/// the near future (herein implemented via an expiring timer).
///
/// Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather
/// an identifier - the connection key) to this queue. A subsequent pop() operation will
/// succeed if and only if the first connection in the queue is ready to be terminated (i.e.
/// its kill timer expired).
///
/// Without using this queue, the muxer would have to walk its entire connection pool
/// (hashmap), whenever it needs to check for expired kill timers. With this queue, both
/// scheduling and termination are performed in constant time. However, since we don't want to
/// waste space on a kill queue that's as big as the connection hashmap itself, it is possible
/// that this queue may become full at times. We call this kill queue "synchronized" if we are
/// certain that all connections that are awaiting termination are present in the queue. This
/// means a simple constant-time pop() operation is enough to check whether any connections
/// need to be terminated. When the kill queue becomes full, though, pushing fails, so
/// connections that should be terminated are left out. The queue is not synchronized anymore.
/// When that happens, the muxer will first drain the queue, and then replace it with a new
/// queue, created by walking the connection pool, looking for connections that will be
/// expiring in the future.
///
use std::collections::{HashMap, VecDeque};
use std::time::Instant;

View File

@@ -2,20 +2,20 @@
// SPDX-License-Identifier: Apache-2.0
//
//! `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest)
//! packets (or rather instructions on how to build said packets).
//!
//! Under ideal operation, every connection, that has pending RX data, will be present in the muxer
//! RX queue. However, since the RX queue is smaller than the connection pool, it may, under some
//! conditions, become full, meaning that it can no longer account for all the connections that can
//! yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the
//! connection pool). A desynchronized RX queue still holds valid data, and the muxer will
//! continue to pop packets from it. However, when a desynchronized queue is drained, additional
//! data may still be available, so the muxer will have to perform a more costly walk of the entire
//! connection pool to find it. This walk is performed here, as part of building an RX queue from
//! the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to
//! rebuild a synced one.
/// `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest)
/// packets (or rather instructions on how to build said packets).
///
/// Under ideal operation, every connection, that has pending RX data, will be present in the muxer
/// RX queue. However, since the RX queue is smaller than the connection pool, it may, under some
/// conditions, become full, meaning that it can no longer account for all the connections that can
/// yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the
/// connection pool). A desynchronized RX queue still holds valid data, and the muxer will
/// continue to pop packets from it. However, when a desynchronized queue is drained, additional
/// data may still be available, so the muxer will have to perform a more costly walk of the entire
/// connection pool to find it. This walk is performed here, as part of building an RX queue from
/// the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to
/// rebuild a synced one.
///
use std::collections::{HashMap, VecDeque};
use super::super::VsockChannel;

View File

@@ -12,8 +12,6 @@
mod address;
mod gsi;
/// page size related utility funtions
pub mod page_size;
mod system;
pub use crate::address::AddressAllocator;

View File

@@ -1,38 +0,0 @@
// Copyright 2023 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use libc::{sysconf, _SC_PAGESIZE};
/// get host page size
pub fn get_page_size() -> u64 {
// SAFETY: FFI call. Trivially safe.
unsafe { sysconf(_SC_PAGESIZE) as u64 }
}
/// round up address to let it align page size
pub fn align_page_size_up(address: u64) -> u64 {
let page_size = get_page_size();
(address + page_size - 1) & !(page_size - 1)
}
/// round down address to let it align page size
pub fn align_page_size_down(address: u64) -> u64 {
let page_size = get_page_size();
address & !(page_size - 1)
}
/// Test if address is 4k aligned
pub fn is_4k_aligned(address: u64) -> bool {
(address & 0xfff) == 0
}
/// Test if size is 4k aligned
pub fn is_4k_multiple(size: u64) -> bool {
(size & 0xfff) == 0
}
/// Test if address is page size aligned
pub fn is_page_size_aligned(address: u64) -> bool {
let page_size = get_page_size();
address & (page_size - 1) == 0
}

View File

@@ -14,7 +14,14 @@ use crate::gsi::GsiAllocator;
#[cfg(target_arch = "x86_64")]
use crate::gsi::GsiApic;
use crate::page_size::get_page_size;
use libc::{sysconf, _SC_PAGESIZE};
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
#[inline(always)]
fn pagesize() -> usize {
// SAFETY: FFI call. Trivially safe.
unsafe { sysconf(_SC_PAGESIZE) as usize }
}
/// Manages allocating system resources such as address space and interrupt numbers.
///
@@ -119,7 +126,7 @@ impl SystemAllocator {
self.platform_mmio_address_space.allocate(
address,
size,
Some(align_size.unwrap_or(get_page_size())),
Some(align_size.unwrap_or(pagesize() as u64)),
)
}
@@ -133,7 +140,7 @@ impl SystemAllocator {
self.mmio_hole_address_space.allocate(
address,
size,
Some(align_size.unwrap_or(get_page_size())),
Some(align_size.unwrap_or(pagesize() as u64)),
)
}

View File

@@ -10,10 +10,10 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.70"
anyhow = "1.0.69"
hypervisor = { path = "../hypervisor" }
thiserror = "1.0.39"
serde = { version = "1.0.156", features = ["rc", "derive"] }
thiserror = "1.0.38"
serde = { version = "1.0.151", features = ["rc", "derive"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.10.0", features = ["backend-mmap"] }
vmm-sys-util = "0.11.0"

View File

@@ -110,7 +110,8 @@ impl Bus {
let devices = self.devices.read().unwrap();
let (range, dev) = devices
.range(..=BusRange { base: addr, len: 1 })
.next_back()?;
.rev()
.next()?;
dev.upgrade().map(|d| (*range, d.clone()))
}

View File

@@ -5,10 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
anyhow = "1.0.70"
thiserror = "1.0.39"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
versionize = "0.1.10"
anyhow = "1.0.69"
thiserror = "1.0.38"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }

View File

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

View File

@@ -9,5 +9,5 @@ default = []
[dependencies]
log = "0.4.17"
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -14,7 +14,7 @@ tracing = ["tracer/tracing"]
[dependencies]
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.70"
anyhow = "1.0.69"
arc-swap = "1.5.1"
arch = { path = "../arch" }
bitflags = "1.3.2"
@@ -22,7 +22,7 @@ block_util = { path = "../block_util" }
devices = { path = "../devices" }
epoll = "4.3.1"
event_monitor = { path = "../event_monitor" }
gdbstub = { version = "0.6.4", optional = true }
gdbstub = { version = "0.6.3", optional = true }
gdbstub_arch = { version = "0.2.4", optional = true }
hypervisor = { path = "../hypervisor" }
libc = "0.2.139"
@@ -35,24 +35,23 @@ option_parser = { path = "../option_parser" }
pci = { path = "../pci" }
qcow = { path = "../qcow" }
seccompiler = "0.3.0"
serde = { version = "1.0.156", features = ["rc", "derive"] }
serde_json = "1.0.96"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.93"
serial_buffer = { path = "../serial_buffer" }
signal-hook = "0.3.15"
thiserror = "1.0.39"
signal-hook = "0.3.14"
thiserror = "1.0.38"
tracer = { path = "../tracer" }
uuid = "1.3.0"
versionize = "0.1.10"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.7.1"
virtio-queue = "0.7.0"
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
zerocopy = "0.6.1"

View File

@@ -9,7 +9,7 @@ use crate::pci_segment::PciSegment;
use crate::{GuestMemoryMmap, GuestRegionMmap};
#[cfg(target_arch = "aarch64")]
use acpi_tables::sdt::GenericAddress;
use acpi_tables::{rsdp::Rsdp, sdt::Sdt, Aml};
use acpi_tables::{aml::Aml, rsdp::Rsdp, sdt::Sdt};
#[cfg(target_arch = "aarch64")]
use arch::aarch64::DeviceInfoForFdt;
#[cfg(target_arch = "aarch64")]
@@ -20,8 +20,7 @@ use pci::PciBdf;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use tracer::trace_scoped;
use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryRegion};
use zerocopy::AsBytes;
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryRegion};
/* Values for Type in APIC sub-headers */
#[cfg(target_arch = "x86_64")]
@@ -41,7 +40,7 @@ pub const ACPI_APIC_GENERIC_TRANSLATOR: u8 = 15;
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct PciRangeEntry {
pub base_address: u64,
pub segment: u16,
@@ -52,7 +51,7 @@ struct PciRangeEntry {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct MemoryAffinity {
pub type_: u8,
pub length: u8,
@@ -69,7 +68,7 @@ struct MemoryAffinity {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct ProcessorLocalX2ApicAffinity {
pub type_: u8,
pub length: u8,
@@ -83,7 +82,7 @@ struct ProcessorLocalX2ApicAffinity {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct ProcessorGiccAffinity {
pub type_: u8,
pub length: u8,
@@ -143,7 +142,7 @@ impl MemoryAffinity {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct ViotVirtioPciNode {
pub type_: u8,
_reserved: u8,
@@ -155,7 +154,7 @@ struct ViotVirtioPciNode {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct ViotPciRangeNode {
pub type_: u8,
_reserved: u8,
@@ -180,9 +179,9 @@ pub fn create_dsdt_table(
let mut bytes = Vec::new();
device_manager.lock().unwrap().to_aml_bytes(&mut bytes);
cpu_manager.lock().unwrap().to_aml_bytes(&mut bytes);
memory_manager.lock().unwrap().to_aml_bytes(&mut bytes);
device_manager.lock().unwrap().append_aml_bytes(&mut bytes);
cpu_manager.lock().unwrap().append_aml_bytes(&mut bytes);
memory_manager.lock().unwrap().append_aml_bytes(&mut bytes);
dsdt.append_slice(&bytes);
dsdt
@@ -239,7 +238,7 @@ fn create_facp_table(dsdt_offset: GuestAddress, device_manager: &Arc<Mutex<Devic
// X_DSDT
facp.write(140, dsdt_offset.0);
// Hypervisor Vendor Identity
facp.write_bytes(268, b"CLOUDHYP");
facp.write(268, b"CLOUDHYP");
facp.update_checksum();
@@ -812,7 +811,7 @@ pub fn create_acpi_tables(
// RSDP
let rsdp = Rsdp::new(*b"CLOUDH", xsdt_offset.0);
guest_mem
.write_slice(rsdp.as_bytes(), rsdp_offset)
.write_slice(rsdp.as_slice(), rsdp_offset)
.expect("Error writing RSDP");
info!(

View File

@@ -36,22 +36,13 @@ impl EndpointHandler for VmCreate {
match &req.body {
Some(body) => {
// Deserialize into a VmConfig
let mut vm_config: VmConfig = match serde_json::from_slice(body.raw())
let vm_config: VmConfig = match serde_json::from_slice(body.raw())
.map_err(HttpError::SerdeJsonDeserialize)
{
Ok(config) => config,
Err(e) => return error_response(e, StatusCode::BadRequest),
};
if let Some(ref mut nets) = vm_config.net {
if nets.iter().any(|net| net.fds.is_some()) {
warn!("Ignoring FDs sent via the HTTP request body");
}
for net in nets {
net.fds = None;
}
}
// Call vm_create()
match vm_create(api_notifier, api_sender, Arc::new(Mutex::new(vm_config)))
.map_err(HttpError::ApiError)

View File

@@ -165,9 +165,7 @@ pub struct VmInfo {
#[derive(Clone, Deserialize, Serialize)]
pub struct VmmPingResponse {
pub build_version: String,
pub version: String,
pub pid: i64,
}
#[derive(Clone, Deserialize, Serialize, Default, Debug)]
@@ -232,6 +230,7 @@ pub enum ApiResponsePayload {
/// This is the response sent by the VMM API server through the mpsc channel.
pub type ApiResponse = std::result::Result<ApiResponsePayload, ApiError>;
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum ApiRequest {
/// Create the virtual machine. This request payload is a VM configuration

View File

@@ -438,13 +438,8 @@ components:
- version
type: object
properties:
build_version:
type: string
version:
type: string
pid:
type: integer
format: int64
description: Virtual Machine Monitor information
VmInfo:

View File

@@ -17,7 +17,7 @@ use std::str::FromStr;
use thiserror::Error;
use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
const MAX_NUM_PCI_SEGMENTS: u16 = 16;
/// Errors associated with VM configuration parameters.
#[derive(Debug, Error)]
@@ -2947,26 +2947,24 @@ mod tests {
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
..Default::default()
});
assert!(still_valid_config.validate().is_ok());
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS + 1,
num_pci_segments: 17,
..Default::default()
});
assert_eq!(
invalid_config.validate(),
Err(ValidationError::InvalidNumPciSegments(
MAX_NUM_PCI_SEGMENTS + 1
))
Err(ValidationError::InvalidNumPciSegments(17))
);
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -2974,18 +2972,18 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
iommu_segments: Some(vec![MAX_NUM_PCI_SEGMENTS + 1, MAX_NUM_PCI_SEGMENTS + 2]),
num_pci_segments: 16,
iommu_segments: Some(vec![17, 18]),
..Default::default()
});
assert_eq!(
invalid_config.validate(),
Err(ValidationError::InvalidPciSegment(MAX_NUM_PCI_SEGMENTS + 1))
Err(ValidationError::InvalidPciSegment(17))
);
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -2998,7 +2996,7 @@ mod tests {
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3011,7 +3009,7 @@ mod tests {
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3024,7 +3022,7 @@ mod tests {
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3037,7 +3035,7 @@ mod tests {
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3050,7 +3048,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3066,7 +3064,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3082,7 +3080,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3098,7 +3096,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3114,7 +3112,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3131,7 +3129,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.memory.shared = true;
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3146,7 +3144,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});
@@ -3162,7 +3160,7 @@ mod tests {
let mut invalid_config = valid_config.clone();
invalid_config.memory.shared = true;
invalid_config.platform = Some(PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
num_pci_segments: 16,
iommu_segments: Some(vec![1, 2, 3]),
..Default::default()
});

View File

@@ -27,7 +27,7 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::vm::physical_bits;
use crate::GuestMemoryMmap;
use crate::CPU_MANAGER_SNAPSHOT_ID;
use acpi_tables::{aml, sdt::Sdt, Aml};
use acpi_tables::{aml, aml::Aml, sdt::Sdt};
use anyhow::anyhow;
#[cfg(all(target_arch = "aarch64", feature = "guest_debug"))]
use arch::aarch64::regs;
@@ -84,7 +84,6 @@ use vm_migration::{
};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::{register_signal_handler, SIGRTMIN};
use zerocopy::AsBytes;
#[cfg(all(target_arch = "aarch64", feature = "guest_debug"))]
/// Extract the specified bits of a 64-bit integer.
@@ -168,16 +167,12 @@ pub enum Error {
#[cfg(target_arch = "x86_64")]
#[error("Error setting up AMX: {0}")]
AmxEnable(#[source] anyhow::Error),
#[error("Maximum number of vCPUs exceeds host limit")]
MaximumVcpusExceeded,
}
pub type Result<T> = result::Result<T, Error>;
#[cfg(target_arch = "x86_64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct LocalApic {
pub r#type: u8,
pub length: u8,
@@ -188,7 +183,7 @@ struct LocalApic {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct Ioapic {
pub r#type: u8,
pub length: u8,
@@ -201,7 +196,6 @@ struct Ioapic {
#[cfg(target_arch = "aarch64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct GicC {
pub r#type: u8,
pub length: u8,
@@ -226,7 +220,6 @@ struct GicC {
#[cfg(target_arch = "aarch64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct GicD {
pub r#type: u8,
pub length: u8,
@@ -241,7 +234,6 @@ struct GicD {
#[cfg(target_arch = "aarch64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct GicR {
pub r#type: u8,
pub length: u8,
@@ -253,7 +245,6 @@ struct GicR {
#[cfg(target_arch = "aarch64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct GicIts {
pub r#type: u8,
pub length: u8,
@@ -266,7 +257,6 @@ struct GicIts {
#[cfg(target_arch = "aarch64")]
#[allow(dead_code)]
#[repr(packed)]
#[derive(AsBytes)]
struct ProcessorHierarchyNode {
pub r#type: u8,
pub length: u8,
@@ -279,7 +269,7 @@ struct ProcessorHierarchyNode {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Default, AsBytes)]
#[derive(Default)]
struct InterruptSourceOverride {
pub r#type: u8,
pub length: u8,
@@ -599,10 +589,6 @@ impl CpuManager {
#[cfg(feature = "tdx")] tdx_enabled: bool,
numa_nodes: &NumaNodes,
) -> Result<Arc<Mutex<CpuManager>>> {
if u32::from(config.max_vcpus) > hypervisor.get_max_vcpus() {
return Err(Error::MaximumVcpusExceeded);
}
let mut vcpu_states = Vec::with_capacity(usize::from(config.max_vcpus));
vcpu_states.resize_with(usize::from(config.max_vcpus), VcpuState::default);
let hypervisor_type = hypervisor.hypervisor_type();
@@ -703,23 +689,14 @@ impl CpuManager {
.sgx_epc_region()
.as_ref()
.map(|sgx_epc_region| sgx_epc_region.epc_sections().values().cloned().collect());
let topology = self.config.topology.clone().map_or_else(
|| {
#[cfg(feature = "mshv")]
if matches!(hypervisor.hypervisor_type(), HypervisorType::Mshv) {
return Some((1, self.boot_vcpus(), 1));
}
None
},
|t| Some((t.threads_per_core, t.cores_per_die, t.dies_per_package)),
);
self.cpuid = {
let phys_bits = physical_bits(self.config.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
topology,
self.config
.topology
.clone()
.map(|t| (t.threads_per_core, t.cores_per_die, t.dies_per_package)),
sgx_epc_sections,
phys_bits,
self.config.kvm_hyperv,
@@ -1131,7 +1108,7 @@ impl CpuManager {
fn remove_vcpu(&mut self, cpu_id: u8) -> Result<()> {
info!("Removing vCPU: cpu_id = {}", cpu_id);
let state = &mut self.vcpu_states[usize::from(cpu_id)];
let mut state = &mut self.vcpu_states[usize::from(cpu_id)];
state.kill.store(true, Ordering::SeqCst);
state.signal_thread();
state.join_thread()?;
@@ -1283,7 +1260,7 @@ impl CpuManager {
let mut madt = Sdt::new(*b"APIC", 44, 5, *b"CLOUDH", *b"CHMADT ", 1);
#[cfg(target_arch = "x86_64")]
{
madt.write(36, arch::layout::APIC_START.0);
madt.write(36, arch::layout::APIC_START);
for cpu in 0..self.config.max_vcpus {
let lapic = LocalApic {
@@ -1749,7 +1726,7 @@ impl Cpu {
}
impl Aml for Cpu {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
#[cfg(target_arch = "x86_64")]
let mat_data: Vec<u8> = self.generate_mat();
#[allow(clippy::if_same_then_else)]
@@ -1790,7 +1767,7 @@ impl Aml for Cpu {
// containing the LAPIC for this processor with the enabled bit set
// even it if is disabled in the MADT (non-boot CPU)
#[cfg(target_arch = "x86_64")]
&aml::Name::new("_MAT".into(), &aml::BufferData::new(mat_data)),
&aml::Name::new("_MAT".into(), &aml::Buffer::new(mat_data)),
// Trigger CPU ejection
#[cfg(target_arch = "x86_64")]
&aml::Method::new(
@@ -1802,7 +1779,7 @@ impl Aml for Cpu {
),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
} else {
aml::Device::new(
format!("C{:03}", self.cpu_id).as_str().into(),
@@ -1827,10 +1804,10 @@ impl Aml for Cpu {
// containing the LAPIC for this processor with the enabled bit set
// even it if is disabled in the MADT (non-boot CPU)
#[cfg(target_arch = "x86_64")]
&aml::Name::new("_MAT".into(), &aml::BufferData::new(mat_data)),
&aml::Name::new("_MAT".into(), &aml::Buffer::new(mat_data)),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
}
}
@@ -1840,13 +1817,13 @@ struct CpuNotify {
}
impl Aml for CpuNotify {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let object = aml::Path::new(&format!("C{:03}", self.cpu_id));
aml::If::new(
&aml::Equal::new(&aml::Arg(0), &self.cpu_id),
vec![&aml::Notify::new(&object, &aml::Arg(1))],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
@@ -1856,7 +1833,7 @@ struct CpuMethods {
}
impl Aml for CpuMethods {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
if self.dynamic {
// CPU status method
aml::Method::new(
@@ -1880,19 +1857,19 @@ impl Aml for CpuMethods {
&aml::Return::new(&aml::Local(0)),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
let mut cpu_notifies = Vec::new();
for cpu_id in 0..self.max_vcpus {
cpu_notifies.push(CpuNotify { cpu_id });
}
let mut cpu_notifies_refs: Vec<&dyn Aml> = Vec::new();
let mut cpu_notifies_refs: Vec<&dyn aml::Aml> = Vec::new();
for cpu_id in 0..self.max_vcpus {
cpu_notifies_refs.push(&cpu_notifies[usize::from(cpu_id)]);
}
aml::Method::new("CTFY".into(), 2, true, cpu_notifies_refs).to_aml_bytes(sink);
aml::Method::new("CTFY".into(), 2, true, cpu_notifies_refs).append_aml_bytes(bytes);
aml::Method::new(
"CEJ0".into(),
@@ -1907,7 +1884,7 @@ impl Aml for CpuMethods {
&aml::Release::new("\\_SB_.PRES.CPLK".into()),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
aml::Method::new(
"CSCN".into(),
@@ -1961,22 +1938,22 @@ impl Aml for CpuMethods {
&aml::Release::new("\\_SB_.PRES.CPLK".into()),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
} else {
aml::Method::new("CSCN".into(), 0, true, vec![]).to_aml_bytes(sink)
aml::Method::new("CSCN".into(), 0, true, vec![]).append_aml_bytes(bytes)
}
}
}
impl Aml for CpuManager {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
#[cfg(target_arch = "x86_64")]
if let Some(acpi_address) = self.acpi_address {
// CPU hotplug controller
aml::Device::new(
"_SB_.PRES".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_UID".into(), &"CPU Hotplug Controller"),
// Mutex to protect concurrent access as we write to choose CPU and then read back status
&aml::Mutex::new("CPLK".into(), 0),
@@ -1993,13 +1970,12 @@ impl Aml for CpuManager {
&aml::OpRegion::new(
"PRST".into(),
aml::OpRegionSpace::SystemMemory,
&(acpi_address.0 as usize),
&CPU_MANAGER_ACPI_SIZE,
acpi_address.0 as usize,
CPU_MANAGER_ACPI_SIZE,
),
&aml::Field::new(
"PRST".into(),
aml::FieldAccessType::Byte,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::WriteAsZeroes,
vec![
aml::FieldEntry::Reserved(32),
@@ -2014,7 +1990,6 @@ impl Aml for CpuManager {
&aml::Field::new(
"PRST".into(),
aml::FieldAccessType::DWord,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::Preserve,
vec![
aml::FieldEntry::Named(*b"CSEL", 32),
@@ -2024,18 +1999,18 @@ impl Aml for CpuManager {
),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
// CPU devices
let hid = aml::Name::new("_HID".into(), &"ACPI0010");
let uid = aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A05"));
let uid = aml::Name::new("_CID".into(), &aml::EisaName::new("PNP0A05"));
// Bundle methods together under a common object
let methods = CpuMethods {
max_vcpus: self.config.max_vcpus,
dynamic: self.dynamic,
};
let mut cpu_data_inner: Vec<&dyn Aml> = vec![&hid, &uid, &methods];
let mut cpu_data_inner: Vec<&dyn aml::Aml> = vec![&hid, &uid, &methods];
let mut cpu_devices = Vec::new();
for cpu_id in 0..self.config.max_vcpus {
@@ -2053,7 +2028,7 @@ impl Aml for CpuManager {
cpu_data_inner.push(cpu_device);
}
aml::Device::new("_SB_.CPUS".into(), cpu_data_inner).to_aml_bytes(sink)
aml::Device::new("_SB_.CPUS".into(), cpu_data_inner).append_aml_bytes(bytes)
}
}

View File

@@ -26,7 +26,7 @@ use crate::GuestRegionMmap;
use crate::PciDeviceInfo;
use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID};
use acpi_tables::sdt::GenericAddress;
use acpi_tables::{aml, Aml};
use acpi_tables::{aml, aml::Aml};
use anyhow::anyhow;
use arch::layout;
#[cfg(target_arch = "x86_64")]
@@ -70,6 +70,7 @@ use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::PathBuf;
use std::result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Instant;
use tracer::trace_scoped;
@@ -100,6 +101,7 @@ use vm_migration::{
use vm_virtio::AccessPlatform;
use vm_virtio::VirtioDeviceType;
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::terminal::Terminal;
#[cfg(target_arch = "aarch64")]
const MMIO_LEN: u64 = 0x1000;
@@ -530,14 +532,6 @@ pub struct Console {
}
impl Console {
pub fn need_resize(&self) -> bool {
if let Some(_resizer) = self.console_resizer.as_ref() {
return true;
}
false
}
pub fn update_console_size(&self) {
if let Some(resizer) = self.console_resizer.as_ref() {
resizer.update_console_size()
@@ -831,8 +825,8 @@ pub struct DeviceManager {
// pty foreground status,
console_resize_pipe: Option<Arc<File>>,
// To restore on exit.
original_termios_opt: Arc<Mutex<Option<termios>>>,
// Are any devices using the tty?
on_tty: Option<Arc<AtomicBool>>,
// Interrupt controller
#[cfg(target_arch = "x86_64")]
@@ -1118,7 +1112,7 @@ impl DeviceManager {
serial_manager: None,
console_pty: None,
console_resize_pipe: None,
original_termios_opt: Arc::new(Mutex::new(None)),
on_tty: None,
virtio_mem_devices: Vec::new(),
#[cfg(target_arch = "aarch64")]
gpio_device: None,
@@ -1166,7 +1160,7 @@ impl DeviceManager {
serial_pty: Option<PtyPair>,
console_pty: Option<PtyPair>,
console_resize_pipe: Option<File>,
original_termios_opt: Arc<Mutex<Option<termios>>>,
on_tty: Arc<AtomicBool>,
) -> DeviceManagerResult<()> {
trace_scoped!("create_devices");
@@ -1222,15 +1216,15 @@ impl DeviceManager {
)?;
}
self.original_termios_opt = original_termios_opt;
self.console = self.add_console_device(
&legacy_interrupt_manager,
&mut virtio_devices,
serial_pty,
console_pty,
console_resize_pipe,
&on_tty,
)?;
self.on_tty = Some(on_tty);
if let Some(tpm) = self.config.clone().lock().unwrap().tpm.as_ref() {
let tpm_dev = self.add_tpm_device(tpm.socket.clone())?;
@@ -1843,7 +1837,7 @@ impl DeviceManager {
}
fn modify_mode<F: FnOnce(&mut termios)>(
&mut self,
&self,
fd: RawFd,
f: F,
) -> vmm_sys_util::errno::Result<()> {
@@ -1860,10 +1854,6 @@ impl DeviceManager {
if ret < 0 {
return vmm_sys_util::errno::errno_result();
}
let mut original_termios_opt = self.original_termios_opt.lock().unwrap();
if original_termios_opt.is_none() {
*original_termios_opt = Some(termios);
}
f(&mut termios);
// SAFETY: Safe because the syscall will only read the extent of termios and we check
// the return result.
@@ -1875,12 +1865,12 @@ impl DeviceManager {
Ok(())
}
fn set_raw_mode(&mut self, f: &mut dyn AsRawFd) -> vmm_sys_util::errno::Result<()> {
fn set_raw_mode(&self, f: &mut dyn AsRawFd) -> vmm_sys_util::errno::Result<()> {
// SAFETY: FFI call. Variable t is guaranteed to be a valid termios from modify_mode.
self.modify_mode(f.as_raw_fd(), |t| unsafe { cfmakeraw(t) })
}
fn listen_for_sigwinch_on_tty(&mut self, pty_sub: File) -> std::io::Result<()> {
fn listen_for_sigwinch_on_tty(&mut self, pty_main: File, pty_sub: File) -> std::io::Result<()> {
let seccomp_filter = get_seccomp_filter(
&self.seccomp_action,
Thread::PtyForeground,
@@ -1888,8 +1878,14 @@ impl DeviceManager {
)
.unwrap();
self.console_resize_pipe =
Some(Arc::new(start_sigwinch_listener(seccomp_filter, pty_sub)?));
match start_sigwinch_listener(seccomp_filter, pty_main, pty_sub) {
Ok(pipe) => {
self.console_resize_pipe = Some(Arc::new(pipe));
}
Err(e) => {
warn!("Ignoring error from setting up SIGWINCH listener: {}", e)
}
}
Ok(())
}
@@ -1899,6 +1895,7 @@ impl DeviceManager {
virtio_devices: &mut Vec<MetaVirtioDevice>,
console_pty: Option<PtyPair>,
resize_pipe: Option<File>,
on_tty: &Arc<AtomicBool>,
) -> DeviceManagerResult<Option<Arc<virtio_devices::ConsoleResizer>>> {
let console_config = self.config.lock().unwrap().console.clone();
let endpoint = match console_config.mode {
@@ -1922,7 +1919,8 @@ impl DeviceManager {
self.config.lock().unwrap().console.file = Some(path.clone());
let file = main.try_clone().unwrap();
assert!(resize_pipe.is_none());
self.listen_for_sigwinch_on_tty(sub).unwrap();
self.listen_for_sigwinch_on_tty(main.try_clone().unwrap(), sub)
.unwrap();
self.console_pty = Some(Arc::new(Mutex::new(PtyPair { main, path })));
Endpoint::PtyPair(file.try_clone().unwrap(), file)
}
@@ -1939,15 +1937,11 @@ impl DeviceManager {
// SAFETY: stdout is valid and owned solely by us.
let mut stdout = unsafe { File::from_raw_fd(stdout) };
on_tty.store(true, Ordering::SeqCst);
// Make sure stdout is in raw mode, if it's a terminal.
let _ = self.set_raw_mode(&mut stdout);
// SAFETY: FFI call. Trivially safe.
if unsafe { libc::isatty(libc::STDOUT_FILENO) } == 1 {
self.listen_for_sigwinch_on_tty(stdout.try_clone().unwrap())
.unwrap();
}
// If an interactive TTY then we can accept input
// SAFETY: FFI call. Trivially safe.
if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } {
@@ -2018,6 +2012,7 @@ impl DeviceManager {
serial_pty: Option<PtyPair>,
console_pty: Option<PtyPair>,
console_resize_pipe: Option<File>,
on_tty: &Arc<AtomicBool>,
) -> DeviceManagerResult<Arc<Console>> {
let serial_config = self.config.lock().unwrap().serial.clone();
let serial_writer: Option<Box<dyn io::Write + Send>> = match serial_config.mode {
@@ -2041,6 +2036,7 @@ impl DeviceManager {
}
ConsoleOutputMode::Tty => {
let mut out = stdout();
on_tty.store(true, Ordering::SeqCst);
let _ = self.set_raw_mode(&mut out);
Some(Box::new(out))
}
@@ -2070,8 +2066,12 @@ impl DeviceManager {
};
}
let console_resizer =
self.add_virtio_console_device(virtio_devices, console_pty, console_resize_pipe)?;
let console_resizer = self.add_virtio_console_device(
virtio_devices,
console_pty,
console_resize_pipe,
on_tty,
)?;
Ok(Arc::new(Console { console_resizer }))
}
@@ -4250,7 +4250,7 @@ fn numa_node_id_from_memory_zone_id(numa_nodes: &NumaNodes, memory_zone_id: &str
struct TpmDevice {}
impl Aml for TpmDevice {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn to_aml_bytes(&self) -> Vec<u8> {
aml::Device::new(
"TPM2".into(),
vec![
@@ -4266,19 +4266,19 @@ impl Aml for TpmDevice {
),
],
)
.to_aml_bytes(sink)
.to_aml_bytes()
}
}
impl Aml for DeviceManager {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
#[cfg(target_arch = "aarch64")]
use arch::aarch64::DeviceInfoForFdt;
let mut pci_scan_methods = Vec::new();
for i in 0..self.pci_segments.len() {
pci_scan_methods.push(aml::MethodCall::new(
format!("\\_SB_.PC{i:02X}.PCNT").as_str().into(),
format!("\\_SB_.PCI{i:X}.PCNT").as_str().into(),
vec![],
));
}
@@ -4291,7 +4291,7 @@ impl Aml for DeviceManager {
aml::Device::new(
"_SB_.PHPR".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_STA".into(), &0x0bu8),
&aml::Name::new("_UID".into(), &"PCI Hotplug Controller"),
&aml::Mutex::new("BLCK".into(), 0),
@@ -4308,13 +4308,12 @@ impl Aml for DeviceManager {
&aml::OpRegion::new(
"PCST".into(),
aml::OpRegionSpace::SystemMemory,
&(self.acpi_address.0 as usize),
&DEVICE_MANAGER_ACPI_SIZE,
self.acpi_address.0 as usize,
DEVICE_MANAGER_ACPI_SIZE,
),
&aml::Field::new(
"PCST".into(),
aml::FieldAccessType::DWord,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::WriteAsZeroes,
vec![
aml::FieldEntry::Named(*b"PCIU", 32),
@@ -4343,10 +4342,10 @@ impl Aml for DeviceManager {
&aml::Method::new("PSCN".into(), 0, true, pci_scan_inner),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
for segment in &self.pci_segments {
segment.to_aml_bytes(sink);
segment.append_aml_bytes(bytes);
}
let mut mbrd_memory = Vec::new();
@@ -4367,12 +4366,12 @@ impl Aml for DeviceManager {
aml::Device::new(
"_SB_.MBRD".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0C02")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0C02")),
&aml::Name::new("_UID".into(), &aml::ZERO),
&aml::Name::new("_CRS".into(), &aml::ResourceTemplate::new(mbrd_memory_refs)),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
// Serial device
#[cfg(target_arch = "x86_64")]
@@ -4396,7 +4395,7 @@ impl Aml for DeviceManager {
&aml::Name::new(
"_HID".into(),
#[cfg(target_arch = "x86_64")]
&aml::EISAName::new("PNP0501"),
&aml::EisaName::new("PNP0501"),
#[cfg(target_arch = "aarch64")]
&"ARMH0011",
),
@@ -4407,7 +4406,7 @@ impl Aml for DeviceManager {
&aml::ResourceTemplate::new(vec![
&aml::Interrupt::new(true, true, false, false, serial_irq),
#[cfg(target_arch = "x86_64")]
&aml::IO::new(0x3f8, 0x3f8, 0, 0x8),
&aml::Io::new(0x3f8, 0x3f8, 0, 0x8),
#[cfg(target_arch = "aarch64")]
&aml::Memory32Fixed::new(
true,
@@ -4418,23 +4417,25 @@ impl Aml for DeviceManager {
),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
aml::Name::new("_S5_".into(), &aml::Package::new(vec![&5u8])).to_aml_bytes(sink);
aml::Name::new("_S5_".into(), &aml::Package::new(vec![&5u8])).append_aml_bytes(bytes);
aml::Device::new(
"_SB_.PWRB".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0C0C")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0C0C")),
&aml::Name::new("_UID".into(), &aml::ZERO),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
if self.config.lock().unwrap().tpm.is_some() {
// Add tpm device
TpmDevice {}.to_aml_bytes(sink);
let tpm_acpi = TpmDevice {};
let tpm_dsdt_data = tpm_acpi.to_aml_bytes();
bytes.extend_from_slice(tpm_dsdt_data.as_slice());
}
self.ged_notification_device
@@ -4442,7 +4443,7 @@ impl Aml for DeviceManager {
.unwrap()
.lock()
.unwrap()
.to_aml_bytes(sink)
.append_aml_bytes(bytes);
}
}
@@ -4655,9 +4656,10 @@ impl Drop for DeviceManager {
handle.virtio_device.lock().unwrap().shutdown();
}
if let Some(termios) = *self.original_termios_opt.lock().unwrap() {
// SAFETY: FFI call
let _ = unsafe { tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios) };
if let Some(ref on_tty) = self.on_tty {
if on_tty.load(Ordering::SeqCst) {
let _ = std::io::stdin().lock().set_canon_mode();
}
}
}
}

View File

@@ -109,8 +109,7 @@ pub struct BftIter<'a> {
impl<'a> BftIter<'a> {
fn new(hash_map: &'a HashMap<String, DeviceNode>) -> Self {
let mut nodes = Vec::with_capacity(hash_map.len());
let mut i = 0;
let mut nodes = Vec::new();
for (_, node) in hash_map.iter() {
if node.parent.is_none() {
@@ -118,13 +117,26 @@ impl<'a> BftIter<'a> {
}
}
while i < nodes.len() {
for child_node_id in nodes[i].children.iter() {
if let Some(child_node) = hash_map.get(child_node_id) {
nodes.push(child_node);
let mut node_layer = nodes.as_slice();
loop {
let mut next_node_layer = Vec::new();
for node in node_layer.iter() {
for child_node_id in node.children.iter() {
if let Some(child_node) = hash_map.get(child_node_id) {
next_node_layer.push(child_node);
}
}
}
i += 1;
if next_node_layer.is_empty() {
break;
}
let pos = nodes.len();
nodes.extend(next_node_layer);
node_layer = &nodes[pos..];
}
BftIter { nodes }

View File

@@ -435,6 +435,7 @@ impl run_blocking::BlockingEventLoop for GdbEventLoop {
type Connection = Box<dyn ConnectionExt<Error = std::io::Error>>;
type StopReason = MultiThreadStopReason<ArchUsize>;
#[allow(clippy::type_complexity)]
fn wait_for_stop_reason(
target: &mut Self::Target,
conn: &mut Self::Connection,

View File

@@ -25,7 +25,7 @@ use crate::migration::{recv_vm_config, recv_vm_state};
use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::vm::{Error as VmError, Vm, VmState};
use anyhow::anyhow;
use libc::{tcsetattr, termios, EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW};
use libc::{EFD_NONBLOCK, SIGINT, SIGTERM};
use memory_manager::MemoryManagerSnapshotData;
use pci::PciBdf;
use seccompiler::{apply_filter, SeccompAction};
@@ -35,12 +35,13 @@ use signal_hook::iterator::{Handle, Signals};
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::{stdout, Read, Write};
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::net::UnixListener;
use std::os::unix::net::UnixStream;
use std::panic::AssertUnwindSafe;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Receiver, RecvError, SendError, Sender};
use std::sync::{Arc, Mutex};
use std::time::Instant;
@@ -53,6 +54,7 @@ use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transport
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::unblock_signal;
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
use vmm_sys_util::terminal::Terminal;
mod acpi;
pub mod api;
@@ -80,6 +82,7 @@ type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
/// Errors associated with VMM management
#[derive(Debug, Error)]
#[allow(clippy::large_enum_variant)]
pub enum Error {
/// API request receive error
#[error("Error receiving API request: {0}")]
@@ -279,7 +282,7 @@ impl Serialize for PciDeviceInfo {
#[allow(unused_variables)]
#[allow(clippy::too_many_arguments)]
pub fn start_vmm_thread(
vmm_version: VmmVersionInfo,
vmm_version: String,
http_path: &Option<String>,
http_fd: Option<RawFd>,
api_event: EventFd,
@@ -288,7 +291,6 @@ pub fn start_vmm_thread(
#[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>,
#[cfg(feature = "guest_debug")] debug_event: EventFd,
#[cfg(feature = "guest_debug")] vm_debug_event: EventFd,
exit_event: EventFd,
seccomp_action: &SeccompAction,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
) -> Result<thread::JoinHandle<Result<()>>> {
@@ -309,8 +311,9 @@ pub fn start_vmm_thread(
.map_err(Error::CreateSeccompFilter)?;
let vmm_seccomp_action = seccomp_action.clone();
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let thread = {
let exit_event = exit_event.try_clone().map_err(Error::EventFdClone)?;
let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?;
thread::Builder::new()
.name("vmm".to_string())
.spawn(move || {
@@ -320,7 +323,7 @@ pub fn start_vmm_thread(
}
let mut vmm = Vmm::new(
vmm_version,
vmm_version.to_string(),
api_event,
#[cfg(feature = "guest_debug")]
debug_event,
@@ -328,7 +331,7 @@ pub fn start_vmm_thread(
vm_debug_event,
vmm_seccomp_action,
hypervisor,
exit_event,
exit_evt,
)?;
vmm.setup_signal_handler()?;
@@ -349,7 +352,7 @@ pub fn start_vmm_thread(
http_api_event,
api_sender,
seccomp_action,
exit_event,
exit_evt,
hypervisor_type,
)?;
} else if let Some(http_fd) = http_fd {
@@ -358,7 +361,7 @@ pub fn start_vmm_thread(
http_api_event,
api_sender,
seccomp_action,
exit_event,
exit_evt,
hypervisor_type,
)?;
}
@@ -388,21 +391,6 @@ struct VmMigrationConfig {
memory_manager_data: MemoryManagerSnapshotData,
}
#[derive(Debug, Clone)]
pub struct VmmVersionInfo {
pub build_version: String,
pub version: String,
}
impl VmmVersionInfo {
pub fn new(build_version: &str, version: &str) -> Self {
Self {
build_version: build_version.to_owned(),
version: version.to_owned(),
}
}
}
pub struct Vmm {
epoll: EpollContext,
exit_evt: EventFd,
@@ -412,7 +400,7 @@ pub struct Vmm {
debug_evt: EventFd,
#[cfg(feature = "guest_debug")]
vm_debug_evt: EventFd,
version: VmmVersionInfo,
version: String,
vm: Option<Vm>,
vm_config: Option<Arc<Mutex<VmConfig>>>,
seccomp_action: SeccompAction,
@@ -420,17 +408,13 @@ pub struct Vmm {
activate_evt: EventFd,
signals: Option<Handle>,
threads: Vec<thread::JoinHandle<()>>,
original_termios_opt: Arc<Mutex<Option<termios>>>,
on_tty: Arc<AtomicBool>,
}
impl Vmm {
pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT];
fn signal_handler(
mut signals: Signals,
original_termios_opt: Arc<Mutex<Option<termios>>>,
exit_evt: &EventFd,
) {
fn signal_handler(mut signals: Signals, on_tty: Arc<AtomicBool>, exit_evt: &EventFd) {
for sig in &Self::HANDLED_SIGNALS {
unblock_signal(*sig).unwrap();
}
@@ -440,17 +424,12 @@ impl Vmm {
SIGTERM | SIGINT => {
if exit_evt.write(1).is_err() {
// Resetting the terminal is usually done as the VMM exits
if let Ok(lock) = original_termios_opt.lock() {
if let Some(termios) = *lock {
// SAFETY: FFI call
let _ = unsafe {
tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios)
};
}
} else {
warn!("Failed to lock original termios");
if on_tty.load(Ordering::SeqCst) {
io::stdin()
.lock()
.set_canon_mode()
.expect("failed to restore terminal mode");
}
std::process::exit(1);
}
}
@@ -465,7 +444,7 @@ impl Vmm {
Ok(signals) => {
self.signals = Some(signals.handle());
let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?;
let original_termios_opt = Arc::clone(&self.original_termios_opt);
let on_tty = Arc::clone(&self.on_tty);
let signal_handler_seccomp_filter = get_seccomp_filter(
&self.seccomp_action,
@@ -487,7 +466,7 @@ impl Vmm {
}
}
std::panic::catch_unwind(AssertUnwindSafe(|| {
Vmm::signal_handler(signals, original_termios_opt, &exit_evt);
Vmm::signal_handler(signals, on_tty, &exit_evt);
}))
.map_err(|_| {
error!("vmm signal_handler thread panicked");
@@ -504,7 +483,7 @@ impl Vmm {
}
fn new(
vmm_version: VmmVersionInfo,
vmm_version: String,
api_evt: EventFd,
#[cfg(feature = "guest_debug")] debug_evt: EventFd,
#[cfg(feature = "guest_debug")] vm_debug_evt: EventFd,
@@ -554,7 +533,7 @@ impl Vmm {
activate_evt,
signals: None,
threads: vec![],
original_termios_opt: Arc::new(Mutex::new(None)),
on_tty: Arc::new(AtomicBool::new(false)),
})
}
@@ -605,7 +584,7 @@ impl Vmm {
None,
None,
None,
Arc::clone(&self.original_termios_opt),
Arc::clone(&self.on_tty),
None,
None,
None,
@@ -704,7 +683,7 @@ impl Vmm {
None,
None,
None,
Arc::clone(&self.original_termios_opt),
Arc::clone(&self.on_tty),
Some(snapshot),
Some(source_url),
Some(restore_cfg.prefault),
@@ -785,7 +764,7 @@ impl Vmm {
serial_pty,
console_pty,
console_resize_pipe,
Arc::clone(&self.original_termios_opt),
Arc::clone(&self.on_tty),
None,
None,
None,
@@ -828,15 +807,8 @@ impl Vmm {
}
fn vmm_ping(&self) -> VmmPingResponse {
let VmmVersionInfo {
build_version,
version,
} = self.version.clone();
VmmPingResponse {
build_version,
version,
pid: std::process::id() as i64,
version: self.version.clone(),
}
}
@@ -1295,7 +1267,7 @@ impl Vmm {
None,
None,
None,
Arc::clone(&self.original_termios_opt),
Arc::clone(&self.on_tty),
Some(snapshot),
)
.map_err(|e| {
@@ -2091,7 +2063,7 @@ mod unit_tests {
fn create_dummy_vmm() -> Vmm {
Vmm::new(
VmmVersionInfo::new("dummy", "dummy"),
"dummy".to_string(),
EventFd::new(EFD_NONBLOCK).unwrap(),
#[cfg(feature = "guest_debug")]
EventFd::new(EFD_NONBLOCK).unwrap(),

View File

@@ -12,7 +12,7 @@ use crate::coredump::{
use crate::migration::url_to_path;
use crate::MEMORY_MANAGER_SNAPSHOT_ID;
use crate::{GuestMemoryMmap, GuestRegionMmap};
use acpi_tables::{aml, Aml};
use acpi_tables::{aml, aml::Aml};
use anyhow::anyhow;
#[cfg(target_arch = "x86_64")]
use arch::x86_64::{SgxEpcRegion, SgxEpcSection};
@@ -31,7 +31,7 @@ use std::convert::TryInto;
use std::ffi;
use std::fs::{File, OpenOptions};
use std::io::{self, Read};
use std::ops::{BitAnd, Deref, Not, Sub};
use std::ops::Deref;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::PathBuf;
use std::result;
@@ -327,15 +327,6 @@ pub enum Error {
#[cfg(target_arch = "aarch64")]
/// Failed to create UEFI flash
CreateUefiFlash(HypervisorVmError),
/// Using a directory as a backing file for memory is not supported
DirectoryAsBackingFileForMemory,
/// Failed to stat filesystem
GetFileSystemBlockSize(io::Error),
/// Memory size is misaligned with default page size or its hugepage size
MisalignedMemorySize,
}
const ENABLE_FLAG: usize = 0;
@@ -359,77 +350,6 @@ fn mmio_address_space_size(phys_bits: u8) -> u64 {
(1 << phys_bits) - (1 << 16)
}
// The `statfs` function can get information of hugetlbfs, and the hugepage size is in the
// `f_bsize` field.
//
// See: https://github.com/torvalds/linux/blob/v6.3/fs/hugetlbfs/inode.c#L1169
fn statfs_get_bsize(path: &str) -> Result<u64, Error> {
let path = std::ffi::CString::new(path).map_err(|_| Error::InvalidMemoryParameters)?;
let mut buf = std::mem::MaybeUninit::<libc::statfs>::uninit();
// SAFETY: FFI call with a valid path and buffer
let ret = unsafe { libc::statfs(path.as_ptr(), buf.as_mut_ptr()) };
if ret != 0 {
return Err(Error::GetFileSystemBlockSize(
std::io::Error::last_os_error(),
));
}
// SAFETY: `buf` is valid at this point
// Because this value is always positive, just convert it directly.
// Note that the `f_bsize` is `i64` in glibc and `u64` in musl, using `as u64` will be warned
// by `clippy` on musl target. To avoid the warning, there should be `as _` instead of
// `as u64`.
let bsize = unsafe { (*buf.as_ptr()).f_bsize } as _;
Ok(bsize)
}
fn memory_zone_get_align_size(zone: &MemoryZoneConfig) -> Result<u64, Error> {
// SAFETY: FFI call. Trivially safe.
let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as u64 };
// There is no backend file and the `hugepages` is disabled, just use system page size.
if zone.file.is_none() && !zone.hugepages {
return Ok(page_size);
}
// The `hugepages` is enabled and the `hugepage_size` is specified, just use it directly.
if zone.hugepages && zone.hugepage_size.is_some() {
return Ok(zone.hugepage_size.unwrap());
}
// There are two scenarios here:
// - `hugepages` is enabled but `hugepage_size` is not specified:
// Call `statfs` for `/dev/hugepages` for getting the default size of hugepage
// - The backing file is specified:
// Call `statfs` for the file and get its `f_bsize`. If the value is larger than the page
// size of normal page, just use the `f_bsize` because the file is in a hugetlbfs. If the
// value is less than or equal to the page size, just use the page size.
let path = zone.file.as_ref().map_or(Ok("/dev/hugepages"), |pathbuf| {
pathbuf.to_str().ok_or(Error::InvalidMemoryParameters)
})?;
let align_size = std::cmp::max(page_size, statfs_get_bsize(path)?);
Ok(align_size)
}
#[inline]
fn align_down<T>(val: T, align: T) -> T
where
T: BitAnd<Output = T> + Not<Output = T> + Sub<Output = T> + From<u8>,
{
val & !(align - 1u8.into())
}
#[inline]
fn is_aligned<T>(val: T, align: T) -> bool
where
T: BitAnd<Output = T> + Sub<Output = T> + From<u8> + PartialEq,
{
(val & (align - 1u8.into())) == 0u8.into()
}
impl BusDevice for MemoryManager {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
if self.selected_slot < self.hotplug_slots.len() {
@@ -519,9 +439,6 @@ impl MemoryManager {
/// - First one mapping entirely the first memory zone on 0-1G range
/// - Second one mapping partially the second memory zone on 1G-3G range
/// - Third one mapping partially the second memory zone on 4G-6G range
/// Also, all memory regions are page-size aligned (e.g. their sizes must
/// be multiple of page-size), which may leave an additional hole in the
/// address space when hugepage is used.
fn create_memory_regions_from_zones(
ram_regions: &[(GuestAddress, usize)],
zones: &[MemoryZoneConfig],
@@ -531,14 +448,9 @@ impl MemoryManager {
let mut zones = zones.to_owned();
let mut mem_regions = Vec::new();
let mut zone = zones.remove(0);
let mut zone_align_size = memory_zone_get_align_size(&zone)?;
let mut zone_offset = 0u64;
let mut zone_offset = 0;
let mut memory_zones = HashMap::new();
if !is_aligned(zone.size, zone_align_size) {
return Err(Error::MisalignedMemorySize);
}
// Add zone id to the list of memory zones.
memory_zones.insert(zone.id.clone(), MemoryZone::default());
@@ -550,20 +462,16 @@ impl MemoryManager {
let mut ram_region_consumed = false;
let mut pull_next_zone = false;
let ram_region_available_size =
align_down(ram_region.1 as u64 - ram_region_offset, zone_align_size);
if ram_region_available_size == 0 {
break;
}
let zone_sub_size = zone.size - zone_offset;
let ram_region_sub_size = ram_region.1 - ram_region_offset;
let zone_sub_size = zone.size as usize - zone_offset;
let file_offset = zone_offset;
let file_offset = zone_offset as u64;
let region_start = ram_region
.0
.checked_add(ram_region_offset)
.checked_add(ram_region_offset as u64)
.ok_or(Error::GuestAddressOverFlow)?;
let region_size = if zone_sub_size <= ram_region_available_size {
if zone_sub_size == ram_region_available_size {
let region_size = if zone_sub_size <= ram_region_sub_size {
if zone_sub_size == ram_region_sub_size {
ram_region_consumed = true;
}
@@ -572,24 +480,21 @@ impl MemoryManager {
zone_sub_size
} else {
zone_offset += ram_region_available_size;
zone_offset += ram_region_sub_size;
ram_region_consumed = true;
ram_region_available_size
ram_region_sub_size
};
info!(
"create ram region for zone {}, region_start: {:#x}, region_size: {:#x}",
zone.id,
region_start.raw_value(),
region_size
);
let region = MemoryManager::create_ram_region(
&zone.file,
file_offset,
region_start,
region_size as usize,
prefault.unwrap_or(zone.prefault),
region_size,
match prefault {
Some(pf) => pf,
None => zone.prefault,
},
zone.shared,
zone.hugepages,
zone.hugepage_size,
@@ -614,10 +519,6 @@ impl MemoryManager {
break;
}
zone = zones.remove(0);
zone_align_size = memory_zone_get_align_size(&zone)?;
if !is_aligned(zone.size, zone_align_size) {
return Err(Error::MisalignedMemorySize);
}
// Check if zone id already exist. In case it does, throw
// an error as we need unique identifiers. Otherwise, add
@@ -669,7 +570,10 @@ impl MemoryManager {
guest_ram_mapping.file_offset,
GuestAddress(guest_ram_mapping.gpa),
guest_ram_mapping.size as usize,
prefault.unwrap_or(zone_config.prefault),
match prefault {
Some(pf) => pf,
None => zone_config.prefault,
},
zone_config.shared,
zone_config.hugepages,
zone_config.hugepage_size,
@@ -1032,7 +936,7 @@ impl MemoryManager {
)
} else {
// Init guest memory
let arch_mem_regions = arch::arch_memory_regions();
let arch_mem_regions = arch::arch_memory_regions(ram_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter()
@@ -1090,7 +994,10 @@ impl MemoryManager {
0,
start_addr,
hotplug_size as usize,
prefault.unwrap_or(zone.prefault),
match prefault {
Some(pf) => pf,
None => zone.prefault,
},
zone.shared,
zone.hugepages,
zone.hugepage_size,
@@ -1364,9 +1271,37 @@ impl MemoryManager {
Ok(FileOffset::new(f, 0))
}
fn open_backing_file(backing_file: &PathBuf, file_offset: u64) -> Result<FileOffset, Error> {
fn open_backing_file(
backing_file: &PathBuf,
file_offset: u64,
size: usize,
) -> Result<FileOffset, Error> {
if backing_file.is_dir() {
Err(Error::DirectoryAsBackingFileForMemory)
warn!(
"Using a directory as a backing file for memory is deprecated \
and will be removed in a future release. (See #5082)"
);
// Override file offset as it does not apply in this case.
info!(
"Ignoring file offset since the backing file is a \
temporary file created from the specified directory."
);
let fs_str = format!("{}{}", backing_file.display(), "/tmpfile_XXXXXX");
let fs = ffi::CString::new(fs_str).unwrap();
let mut path = fs.as_bytes_with_nul().to_owned();
let path_ptr = path.as_mut_ptr() as *mut _;
// SAFETY: FFI call
let fd = unsafe { libc::mkstemp(path_ptr) };
if fd == -1 {
return Err(Error::SharedFileCreate(std::io::Error::last_os_error()));
}
// SAFETY: FFI call
unsafe { libc::unlink(path_ptr) };
// SAFETY: fd is valid
let f = unsafe { File::from_raw_fd(fd) };
f.set_len(size as u64).map_err(Error::SharedFileSetLen)?;
Ok(FileOffset::new(f, 0))
} else {
let f = OpenOptions::new()
.read(true)
@@ -1406,7 +1341,7 @@ impl MemoryManager {
} else {
mmap_flags |= libc::MAP_PRIVATE;
}
Some(Self::open_backing_file(backing_file, file_offset)?)
Some(Self::open_backing_file(backing_file, file_offset, size)?)
} else if shared || hugepages {
// For hugepages we must also MAP_SHARED otherwise we will trigger #4805
// because the MAP_PRIVATE will trigger CoW against the backing file with
@@ -1591,7 +1526,7 @@ impl MemoryManager {
.ok_or(Error::MemoryRangeAllocation)?;
// Update the slot so that it can be queried via the I/O port
let slot = &mut self.hotplug_slots[self.next_hotplug_slot];
let mut slot = &mut self.hotplug_slots[self.next_hotplug_slot];
slot.active = true;
slot.inserting = true;
slot.base = region.start_addr().0;
@@ -2159,13 +2094,13 @@ struct MemoryNotify {
}
impl Aml for MemoryNotify {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let object = aml::Path::new(&format!("M{:03}", self.slot_id));
aml::If::new(
&aml::Equal::new(&aml::Arg(0), &self.slot_id),
vec![&aml::Notify::new(&object, &aml::Arg(1))],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
@@ -2174,11 +2109,11 @@ struct MemorySlot {
}
impl Aml for MemorySlot {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
aml::Device::new(
format!("M{:03}", self.slot_id).as_str().into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0C80")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0C80")),
&aml::Name::new("_UID".into(), &self.slot_id),
/*
_STA return value:
@@ -2212,7 +2147,7 @@ impl Aml for MemorySlot {
),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
@@ -2221,9 +2156,9 @@ struct MemorySlots {
}
impl Aml for MemorySlots {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
for slot_id in 0..self.slots {
MemorySlot { slot_id }.to_aml_bytes(sink);
MemorySlot { slot_id }.append_aml_bytes(bytes);
}
}
}
@@ -2233,19 +2168,19 @@ struct MemoryMethods {
}
impl Aml for MemoryMethods {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
// Add "MTFY" notification method
let mut memory_notifies = Vec::new();
for slot_id in 0..self.slots {
memory_notifies.push(MemoryNotify { slot_id });
}
let mut memory_notifies_refs: Vec<&dyn Aml> = Vec::new();
let mut memory_notifies_refs: Vec<&dyn aml::Aml> = Vec::new();
for memory_notifier in memory_notifies.iter() {
memory_notifies_refs.push(memory_notifier);
}
aml::Method::new("MTFY".into(), 2, true, memory_notifies_refs).to_aml_bytes(sink);
aml::Method::new("MTFY".into(), 2, true, memory_notifies_refs).append_aml_bytes(bytes);
// MSCN method
aml::Method::new(
@@ -2291,7 +2226,7 @@ impl Aml for MemoryMethods {
&aml::Release::new("MLCK".into()),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
// Memory status method
aml::Method::new(
@@ -2315,7 +2250,7 @@ impl Aml for MemoryMethods {
&aml::Return::new(&aml::Local(0)),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
// Memory range method
aml::Method::new(
@@ -2336,36 +2271,12 @@ impl Aml for MemoryMethods {
0xFFFF_FFFF_FFFF_FFFEu64,
)]),
),
&aml::CreateQWordField::new(
&aml::Path::new("MINL"),
&aml::Path::new("MR64"),
&14usize,
),
&aml::CreateDWordField::new(
&aml::Path::new("MINH"),
&aml::Path::new("MR64"),
&18usize,
),
&aml::CreateQWordField::new(
&aml::Path::new("MAXL"),
&aml::Path::new("MR64"),
&22usize,
),
&aml::CreateDWordField::new(
&aml::Path::new("MAXH"),
&aml::Path::new("MR64"),
&26usize,
),
&aml::CreateQWordField::new(
&aml::Path::new("LENL"),
&aml::Path::new("MR64"),
&38usize,
),
&aml::CreateDWordField::new(
&aml::Path::new("LENH"),
&aml::Path::new("MR64"),
&42usize,
),
&aml::CreateField::<u64>::new(&aml::Path::new("MR64"), &14usize, "MINL".into()),
&aml::CreateField::<u32>::new(&aml::Path::new("MR64"), &18usize, "MINH".into()),
&aml::CreateField::<u64>::new(&aml::Path::new("MR64"), &22usize, "MAXL".into()),
&aml::CreateField::<u32>::new(&aml::Path::new("MR64"), &26usize, "MAXH".into()),
&aml::CreateField::<u64>::new(&aml::Path::new("MR64"), &38usize, "LENL".into()),
&aml::CreateField::<u32>::new(&aml::Path::new("MR64"), &42usize, "LENH".into()),
&aml::Store::new(&aml::Path::new("MINL"), &aml::Path::new("\\_SB_.MHPC.MHBL")),
&aml::Store::new(&aml::Path::new("MINH"), &aml::Path::new("\\_SB_.MHPC.MHBH")),
&aml::Store::new(&aml::Path::new("LENL"), &aml::Path::new("\\_SB_.MHPC.MHLL")),
@@ -2394,18 +2305,18 @@ impl Aml for MemoryMethods {
&aml::Return::new(&aml::Path::new("MR64")),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
impl Aml for MemoryManager {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
if let Some(acpi_address) = self.acpi_address {
// Memory Hotplug Controller
aml::Device::new(
"_SB_.MHPC".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_UID".into(), &"Memory Hotplug Controller"),
// Mutex to protect concurrent access as we write to choose slot and then read back status
&aml::Mutex::new("MLCK".into(), 0),
@@ -2422,13 +2333,12 @@ impl Aml for MemoryManager {
&aml::OpRegion::new(
"MHPR".into(),
aml::OpRegionSpace::SystemMemory,
&(acpi_address.0 as usize),
&MEMORY_MANAGER_ACPI_SIZE,
acpi_address.0 as usize,
MEMORY_MANAGER_ACPI_SIZE,
),
&aml::Field::new(
"MHPR".into(),
aml::FieldAccessType::DWord,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::Preserve,
vec![
aml::FieldEntry::Named(*b"MHBL", 32), // Base (low 4 bytes)
@@ -2440,7 +2350,6 @@ impl Aml for MemoryManager {
&aml::Field::new(
"MHPR".into(),
aml::FieldAccessType::DWord,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::Preserve,
vec![
aml::FieldEntry::Reserved(128),
@@ -2450,7 +2359,6 @@ impl Aml for MemoryManager {
&aml::Field::new(
"MHPR".into(),
aml::FieldAccessType::Byte,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::WriteAsZeroes,
vec![
aml::FieldEntry::Reserved(160),
@@ -2463,7 +2371,6 @@ impl Aml for MemoryManager {
&aml::Field::new(
"MHPR".into(),
aml::FieldAccessType::DWord,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::Preserve,
vec![
aml::FieldEntry::Named(*b"MSEL", 32), // Selector
@@ -2479,18 +2386,18 @@ impl Aml for MemoryManager {
},
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
} else {
aml::Device::new(
"_SB_.MHPC".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_UID".into(), &"Memory Hotplug Controller"),
// Empty MSCN for GED
&aml::Method::new("MSCN".into(), 0, true, vec![]),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
#[cfg(target_arch = "x86_64")]
@@ -2502,7 +2409,7 @@ impl Aml for MemoryManager {
aml::Device::new(
"_SB_.EPC_".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("INT0E0C")),
&aml::Name::new("_HID".into(), &aml::EisaName::new("INT0E0C")),
// QWORD describing the EPC region start and size
&aml::Name::new(
"_CRS".into(),
@@ -2516,7 +2423,7 @@ impl Aml for MemoryManager {
&aml::Method::new("_STA".into(), 0, false, vec![&aml::Return::new(&0xfu8)]),
],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
}
}

View File

@@ -10,7 +10,7 @@
//
use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult};
use acpi_tables::{self, aml, Aml};
use acpi_tables::aml::{self, Aml};
use arch::layout;
use pci::{DeviceRelocation, PciBdf, PciBus, PciConfigMmio, PciRoot};
#[cfg(target_arch = "x86_64")]
@@ -171,7 +171,7 @@ struct PciDevSlot {
}
impl Aml for PciDevSlot {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let sun = self.device_id;
let adr: u32 = (self.device_id as u32) << 16;
aml::Device::new(
@@ -190,7 +190,7 @@ impl Aml for PciDevSlot {
),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
@@ -199,33 +199,33 @@ struct PciDevSlotNotify {
}
impl Aml for PciDevSlotNotify {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let device_id_mask: u32 = 1 << self.device_id;
let object = aml::Path::new(&format!("S{:03}", self.device_id));
aml::And::new(&aml::Local(0), &aml::Arg(0), &device_id_mask).to_aml_bytes(sink);
aml::And::new(&aml::Local(0), &aml::Arg(0), &device_id_mask).append_aml_bytes(bytes);
aml::If::new(
&aml::Equal::new(&aml::Local(0), &device_id_mask),
vec![&aml::Notify::new(&object, &aml::Arg(1))],
)
.to_aml_bytes(sink);
.append_aml_bytes(bytes);
}
}
struct PciDevSlotMethods {}
impl Aml for PciDevSlotMethods {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let mut device_notifies = Vec::new();
for device_id in 0..32 {
device_notifies.push(PciDevSlotNotify { device_id });
}
let mut device_notifies_refs: Vec<&dyn Aml> = Vec::new();
let mut device_notifies_refs: Vec<&dyn aml::Aml> = Vec::new();
for device_notify in device_notifies.iter() {
device_notifies_refs.push(device_notify);
}
aml::Method::new("DVNT".into(), 2, true, device_notifies_refs).to_aml_bytes(sink);
aml::Method::new("DVNT".into(), 2, true, device_notifies_refs).append_aml_bytes(bytes);
aml::Method::new(
"PCNT".into(),
0,
@@ -244,14 +244,14 @@ impl Aml for PciDevSlotMethods {
&aml::Release::new("\\_SB_.PHPR.BLCK".into()),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
struct PciDsmMethod {}
impl Aml for PciDsmMethod {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
// Refer to ACPI spec v6.3 Ch 9.1.1 and PCI Firmware spec v3.3 Ch 4.6.1
// _DSM (Device Specific Method), the following is the implementation in ASL.
/*
@@ -292,11 +292,11 @@ impl Aml for PciDsmMethod {
false,
vec![
&aml::If::new(
&aml::Equal::new(&aml::Arg(0), &aml::BufferData::new(uuid_buf)),
&aml::Equal::new(&aml::Arg(0), &aml::Buffer::new(uuid_buf)),
vec![
&aml::If::new(
&aml::Equal::new(&aml::Arg(2), &aml::ZERO),
vec![&aml::Return::new(&aml::BufferData::new(vec![0x21]))],
vec![&aml::Return::new(&aml::Buffer::new(vec![0x21]))],
),
&aml::If::new(
&aml::Equal::new(&aml::Arg(2), &0x05u8),
@@ -304,19 +304,19 @@ impl Aml for PciDsmMethod {
),
],
),
&aml::Return::new(&aml::BufferData::new(vec![0])),
&aml::Return::new(&aml::Buffer::new(vec![0])),
],
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}
impl Aml for PciSegment {
fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
let mut pci_dsdt_inner_data: Vec<&dyn Aml> = Vec::new();
let hid = aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08"));
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
let mut pci_dsdt_inner_data: Vec<&dyn aml::Aml> = Vec::new();
let hid = aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A08"));
pci_dsdt_inner_data.push(&hid);
let cid = aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A03"));
let cid = aml::Name::new("_CID".into(), &aml::EisaName::new("PNP0A03"));
pci_dsdt_inner_data.push(&cid);
let adr = aml::Name::new("_ADR".into(), &aml::ZERO);
pci_dsdt_inner_data.push(&adr);
@@ -346,7 +346,7 @@ impl Aml for PciSegment {
&aml::ResourceTemplate::new(vec![
&aml::AddressSpace::new_bus_number(0x0u16, 0x0u16),
#[cfg(target_arch = "x86_64")]
&aml::IO::new(0xcf8, 0xcf8, 1, 0x8),
&aml::Io::new(0xcf8, 0xcf8, 1, 0x8),
&aml::AddressSpace::new_memory(
aml::AddressSpaceCachable::NotCacheable,
true,
@@ -418,9 +418,9 @@ impl Aml for PciSegment {
pci_dsdt_inner_data.push(&prt);
aml::Device::new(
format!("_SB_.PC{:02X}", self.id).as_str().into(),
format!("_SB_.PCI{:X}", self.id).as_str().into(),
pci_dsdt_inner_data,
)
.to_aml_bytes(sink)
.append_aml_bytes(bytes)
}
}

View File

@@ -41,7 +41,6 @@ macro_rules! or {
const TCGETS: u64 = 0x5401;
const TCSETS: u64 = 0x5402;
const TIOCSCTTY: u64 = 0x540E;
const TIOCGPGRP: u64 = 0x540F;
const TIOCSPGRP: u64 = 0x5410;
const TIOCGWINSZ: u64 = 0x5413;
const TIOCSPTLCK: u64 = 0x4004_5431;
@@ -168,7 +167,6 @@ mod mshv {
pub const MSHV_GET_GPA_ACCESS_STATES: u64 = 0xc01c_b812;
pub const MSHV_VP_TRANSLATE_GVA: u64 = 0xc020_b80e;
pub const MSHV_CREATE_PARTITION: u64 = 0x4030_b801;
pub const MSHV_VP_REGISTER_INTERCEPT_RESULT: u64 = 0x4030_b817;
}
#[cfg(feature = "mshv")]
use mshv::*;
@@ -198,12 +196,6 @@ fn create_vmm_ioctl_seccomp_rule_common_mshv() -> Result<Vec<SeccompRule>, Backe
and![Cond::new(1, ArgLen::Dword, Eq, MSHV_GET_GPA_ACCESS_STATES)?],
and![Cond::new(1, ArgLen::Dword, Eq, MSHV_VP_TRANSLATE_GVA)?],
and![Cond::new(1, ArgLen::Dword, Eq, MSHV_CREATE_PARTITION)?],
and![Cond::new(
1,
ArgLen::Dword,
Eq,
MSHV_VP_REGISTER_INTERCEPT_RESULT
)?],
])
}
@@ -272,7 +264,6 @@ fn create_vmm_ioctl_seccomp_rule_common(
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, TIOCGPGRP)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGTPEER)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
@@ -464,7 +455,6 @@ 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, TIOCGPGRP)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPGRP)?],
])
@@ -484,7 +474,6 @@ fn pty_foreground_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
#[cfg(target_arch = "aarch64")]
(libc::SYS_ppoll, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_restart_syscall, vec![]),
(libc::SYS_rt_sigaction, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_setsid, vec![]),
@@ -509,7 +498,6 @@ fn vmm_thread_rules(
(libc::SYS_clone, vec![]),
(libc::SYS_clone3, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_close_range, vec![]),
(libc::SYS_connect, vec![]),
(libc::SYS_dup, vec![]),
(libc::SYS_epoll_create1, vec![]),
@@ -531,7 +519,6 @@ fn vmm_thread_rules(
#[cfg(target_arch = "aarch64")]
(libc::SYS_newfstatat, vec![]),
(libc::SYS_futex, vec![]),
(libc::SYS_getdents64, vec![]),
(libc::SYS_getpgid, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_getpgrp, vec![]),
@@ -610,7 +597,6 @@ fn vmm_thread_rules(
(libc::SYS_socketpair, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_stat, vec![]),
(libc::SYS_statfs, vec![]),
(libc::SYS_statx, vec![]),
(libc::SYS_tgkill, vec![]),
(libc::SYS_timerfd_create, vec![]),
@@ -717,7 +703,6 @@ fn vcpu_thread_rules(
(libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_mremap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_nanosleep, vec![]),
(libc::SYS_newfstatat, vec![]),

View File

@@ -1,19 +1,16 @@
// Copyright 2021, 2023 Alyssa Ross <hi@alyssa.is>
// Copyright 2021 Alyssa Ross <hi@alyssa.is>
// SPDX-License-Identifier: Apache-2.0
use crate::clone3::{clone3, clone_args, CLONE_CLEAR_SIGHAND};
use arch::_NSIG;
use libc::{
c_int, c_void, close, fork, getpgrp, ioctl, pipe2, poll, pollfd, setsid, sigemptyset,
siginfo_t, signal, sigprocmask, syscall, tcgetpgrp, tcsetpgrp, SYS_close_range, EINVAL, ENOSYS,
ENOTTY, O_CLOEXEC, POLLERR, SIGWINCH, SIG_DFL, SIG_SETMASK, STDERR_FILENO, TIOCSCTTY,
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::collections::BTreeSet;
use std::fs::{read_dir, File};
use std::fs::File;
use std::io::{self, ErrorKind, Read, Write};
use std::iter::once;
use std::mem::size_of;
use std::mem::MaybeUninit;
use std::os::unix::prelude::*;
@@ -63,107 +60,17 @@ fn unblock_all_signals() -> io::Result<()> {
Ok(())
}
/// # Safety
///
/// Caller is responsible for ensuring all file descriptors not listed
/// in `keep_fds` are not accessed after this point, and that no other
/// thread is opening file descriptors while this function is
/// running.
unsafe fn close_fds_fallback(keep_fds: &BTreeSet<RawFd>) {
// We collect these instead of iterating through them, because we
// don't want to close the descriptor for /proc/self/fd while
// we're iterating through it.
let open_fds: BTreeSet<RawFd> = read_dir("/proc/self/fd")
.unwrap()
.map(Result::unwrap)
.filter_map(|s| s.file_name().into_string().ok()?.parse().ok())
.collect();
for fd in open_fds.difference(keep_fds) {
close(*fd);
}
}
/// # Safety
///
/// Caller is responsible for ensuring all file descriptors not listed
/// in `keep_fds` are not accessed after this point, and that no other
/// thread is opening file descriptors while this function is
/// running.
unsafe fn close_unused_fds(keep_fds: &mut [RawFd]) {
keep_fds.sort();
// Iterate over the gaps between descriptors we want to keep.
let firsts = keep_fds.iter().map(|fd| fd + 1);
for (i, first) in once(0).chain(firsts).enumerate() {
// The next fd is the one at i, because the indexes in the
// iterator are offset by one due to the initial 0.
let next_keep_fd = keep_fds.get(i);
let last = next_keep_fd.map(|fd| fd - 1).unwrap_or(RawFd::MAX);
if first > last {
continue;
}
if syscall(SYS_close_range, first, last, 0) == -1 {
// The kernel might be too old to have close_range, in
// which case we need to fall back to an uglier method.
let e = io::Error::last_os_error();
if e.raw_os_error() == Some(ENOSYS) {
return close_fds_fallback(&keep_fds.iter().copied().collect());
}
panic!("close_range: {e}");
}
}
}
fn set_foreground_process_group(tty: &mut File) -> io::Result<()> {
// SAFETY: trivially safe.
let my_pgrp = unsafe { getpgrp() };
// SAFETY: we have borrowed tty.
let tty_pgrp = unsafe { tcgetpgrp(tty.as_raw_fd()) };
if tty_pgrp == -1 {
let e = io::Error::last_os_error();
if e.raw_os_error() != Some(ENOTTY) {
return Err(e);
}
}
if tty_pgrp == my_pgrp {
return Ok(());
}
// SAFETY: trivially safe.
let my_pgrp = unsafe { setsid() };
if my_pgrp == -1 {
return Err(io::Error::last_os_error());
}
// Set the tty to be this process's controlling terminal.
// SAFETY: we have borrowed tty.
if unsafe { ioctl(tty.as_raw_fd(), TIOCSCTTY, 0) } == -1 {
return Err(io::Error::last_os_error());
}
// Become the foreground process group of the tty.
// SAFETY: we have borrowed tty.
if unsafe { tcsetpgrp(tty.as_raw_fd(), my_pgrp) } == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
}
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, mut tty: File) -> ! {
// SAFETY: any references to these file descriptors are
// unreachable, because this function never returns.
unsafe {
close_unused_fds(&mut [STDERR_FILENO, tx.as_raw_fd(), tty.as_raw_fd()]);
}
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, pty: File) -> ! {
TX.with(|opt| opt.replace(Some(tx)));
let pty_fd = pty.into_raw_fd();
// SAFETY: FFI calls
unsafe {
close(STDIN_FILENO);
close(STDOUT_FILENO);
}
unblock_all_signals().unwrap();
if !seccomp_filter.is_empty() {
@@ -172,8 +79,20 @@ fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, mut tty: File) -
register_signal_handler(SIGWINCH, sigwinch_handler).unwrap();
set_foreground_process_group(&mut tty).unwrap();
drop(tty);
// SAFETY: FFI calls
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(pty_fd, TIOCSCTTY, 0), -1);
// Become the foreground process group of the tty.
assert_ne!(tcsetpgrp(pty_fd, getpgrp()), -1);
// Close the PTY fd
assert_ne!(close(pty_fd), -1);
}
notify();
@@ -200,36 +119,11 @@ fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, mut tty: File) -
exit(0);
}
/// # Safety
///
/// Same as [`fork`].
unsafe fn clone_clear_sighand() -> io::Result<u64> {
let mut args = clone_args::default();
args.flags |= CLONE_CLEAR_SIGHAND;
let r = clone3(&mut args, size_of::<clone_args>());
if r != -1 {
return Ok(r.try_into().unwrap());
}
let e = io::Error::last_os_error();
if e.raw_os_error() != Some(ENOSYS) && e.raw_os_error() != Some(EINVAL) {
return Err(e);
}
// If CLONE_CLEAR_SIGHAND isn't available, fall back to resetting
// all the signal handlers one by one.
let r = fork();
if r == -1 {
return Err(io::Error::last_os_error());
}
if r == 0 {
for signum in 1.._NSIG {
let _ = signal(signum, SIG_DFL);
}
}
Ok(r.try_into().unwrap())
}
pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, tty_sub: File) -> io::Result<File> {
pub fn start_sigwinch_listener(
seccomp_filter: BpfProgram,
pty_main: File,
pty_sub: File,
) -> io::Result<File> {
let mut pipe = [-1; 2];
// SAFETY: FFI call with valid arguments
if unsafe { pipe2(pipe.as_mut_ptr(), O_CLOEXEC) } == -1 {
@@ -241,9 +135,18 @@ pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, tty_sub: File) -> io:
// SAFETY: pipe[1] is valid
let tx = unsafe { File::from_raw_fd(pipe[1]) };
let mut args = clone_args::default();
args.flags |= CLONE_CLEAR_SIGHAND;
// SAFETY: FFI call
if unsafe { clone_clear_sighand() }? == 0 {
sigwinch_listener_main(seccomp_filter, tx, tty_sub);
match unsafe { clone3(&mut args, size_of::<clone_args>()) } {
-1 => return Err(io::Error::last_os_error()),
0 => {
drop(rx);
drop(pty_main);
sigwinch_listener_main(seccomp_filter, tx, pty_sub);
}
_ => (),
}
drop(tx);

View File

@@ -21,7 +21,7 @@ use crate::coredump::{
CpuElf64Writable, DumpState, Elf64Writable, GuestDebuggable, GuestDebuggableError, NoteDescType,
};
use crate::cpu;
use crate::device_manager::{DeviceManager, DeviceManagerError, PtyPair};
use crate::device_manager::{Console, DeviceManager, DeviceManagerError, PtyPair};
use crate::device_tree::DeviceTree;
#[cfg(feature = "guest_debug")]
use crate::gdb::{Debuggable, DebuggableError, GdbRequestPayload, GdbResponsePayload};
@@ -33,6 +33,7 @@ use crate::migration::get_vm_snapshot;
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use crate::migration::url_to_file;
use crate::migration::{url_to_path, SNAPSHOT_CONFIG_FILE, SNAPSHOT_STATE_FILE};
use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::GuestMemoryMmap;
use crate::{
PciDeviceInfo, CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID,
@@ -55,7 +56,6 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs;
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs;
use hypervisor::{HypervisorVmError, VmOps};
use libc::{termios, SIGWINCH};
use linux_loader::cmdline::Cmdline;
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use linux_loader::elf;
@@ -64,8 +64,9 @@ use linux_loader::loader::elf::PvhBootCapability::PvhEntryPresent;
#[cfg(target_arch = "aarch64")]
use linux_loader::loader::pe::Error::InvalidImageMagicNumber;
use linux_loader::loader::KernelLoader;
use seccompiler::SeccompAction;
use seccompiler::{apply_filter, SeccompAction};
use serde::{Deserialize, Serialize};
use signal_hook::{consts::SIGWINCH, iterator::backend::Handle, iterator::Signals};
use std::cmp;
use std::collections::BTreeMap;
use std::collections::HashMap;
@@ -79,6 +80,8 @@ use std::mem::size_of;
use std::num::Wrapping;
use std::ops::Deref;
use std::os::unix::net::UnixStream;
use std::panic::AssertUnwindSafe;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex, RwLock};
use std::time::Instant;
use std::{result, str, thread};
@@ -94,6 +97,7 @@ use vm_migration::{
SnapshotData, Snapshottable, Transportable,
};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::unblock_signal;
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
/// Errors associated with VM management
@@ -314,10 +318,10 @@ impl VmState {
fn valid_transition(self, new_state: VmState) -> Result<()> {
match self {
VmState::Created => match new_state {
VmState::Created => Err(Error::InvalidStateTransition(self, new_state)),
VmState::Running | VmState::Paused | VmState::BreakPoint | VmState::Shutdown => {
Ok(())
VmState::Created | VmState::Shutdown => {
Err(Error::InvalidStateTransition(self, new_state))
}
VmState::Running | VmState::Paused | VmState::BreakPoint => Ok(()),
},
VmState::Running => match new_state {
@@ -430,6 +434,7 @@ pub struct Vm {
threads: Vec<thread::JoinHandle<()>>,
device_manager: Arc<Mutex<DeviceManager>>,
config: Arc<Mutex<VmConfig>>,
signals: Option<Handle>,
state: RwLock<VmState>,
cpu_manager: Arc<Mutex<cpu::CpuManager>>,
memory_manager: Arc<Mutex<MemoryManager>>,
@@ -439,7 +444,8 @@ pub struct Vm {
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
saved_clock: Option<hypervisor::ClockData>,
numa_nodes: NumaNodes,
#[cfg_attr(any(not(feature = "kvm"), target_arch = "aarch64"), allow(dead_code))]
seccomp_action: SeccompAction,
exit_evt: EventFd,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
stop_on_boot: bool,
load_payload_handle: Option<thread::JoinHandle<Result<EntryPoint>>>,
@@ -463,7 +469,7 @@ impl Vm {
serial_pty: Option<PtyPair>,
console_pty: Option<PtyPair>,
console_resize_pipe: Option<File>,
original_termios: Arc<Mutex<Option<termios>>>,
on_tty: Arc<AtomicBool>,
snapshot: Option<Snapshot>,
) -> Result<Self> {
trace_scoped!("Vm::new_from_memory_manager");
@@ -585,12 +591,7 @@ impl Vm {
device_manager
.lock()
.unwrap()
.create_devices(
serial_pty,
console_pty,
console_resize_pipe,
original_termios,
)
.create_devices(serial_pty, console_pty, console_resize_pipe, on_tty)
.map_err(Error::DeviceManager)?;
#[cfg(feature = "tdx")]
@@ -635,6 +636,7 @@ impl Vm {
device_manager,
config,
threads: Vec::with_capacity(1),
signals: None,
state: RwLock::new(vm_state),
cpu_manager,
memory_manager,
@@ -642,6 +644,8 @@ impl Vm {
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
saved_clock,
numa_nodes,
seccomp_action: seccomp_action.clone(),
exit_evt,
hypervisor,
stop_on_boot,
load_payload_handle,
@@ -740,7 +744,7 @@ impl Vm {
serial_pty: Option<PtyPair>,
console_pty: Option<PtyPair>,
console_resize_pipe: Option<File>,
original_termios: Arc<Mutex<Option<termios>>>,
on_tty: Arc<AtomicBool>,
snapshot: Option<Snapshot>,
source_url: Option<&str>,
prefault: Option<bool>,
@@ -810,7 +814,7 @@ impl Vm {
serial_pty,
console_pty,
console_resize_pipe,
original_termios,
on_tty,
snapshot,
)
}
@@ -1201,6 +1205,11 @@ impl Vm {
state.valid_transition(new_state)?;
// Trigger the termination of the signal_handler thread
if let Some(signals) = self.signals.take() {
signals.close();
}
// Wake up the DeviceManager threads so they will get terminated cleanly
self.device_manager
.lock()
@@ -1258,7 +1267,7 @@ impl Vm {
.resize(desired_memory)
.map_err(Error::MemoryManager)?;
let memory_config = &mut self.config.lock().unwrap().memory;
let mut memory_config = &mut self.config.lock().unwrap().memory;
if let Some(new_region) = &new_region {
self.device_manager
@@ -1606,6 +1615,18 @@ impl Vm {
Ok(self.device_manager.lock().unwrap().counters())
}
fn signal_handler(mut signals: Signals, console_input_clone: Arc<Console>) {
for sig in &Vm::HANDLED_SIGNALS {
unblock_signal(*sig).unwrap();
}
for signal in signals.forever() {
if signal == SIGWINCH {
console_input_clone.update_console_size();
}
}
}
#[cfg(feature = "tdx")]
fn extract_tdvf_sections(&mut self) -> Result<(Vec<TdvfSection>, bool)> {
use arch::x86_64::tdx::*;
@@ -1902,6 +1923,49 @@ impl Vm {
Ok(())
}
fn setup_signal_handler(&mut self) -> Result<()> {
let console = self.device_manager.lock().unwrap().console().clone();
let signals = Signals::new(Vm::HANDLED_SIGNALS);
match signals {
Ok(signals) => {
self.signals = Some(signals.handle());
let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?;
let signal_handler_seccomp_filter = get_seccomp_filter(
&self.seccomp_action,
Thread::SignalHandler,
self.hypervisor.hypervisor_type(),
)
.map_err(Error::CreateSeccompFilter)?;
self.threads.push(
thread::Builder::new()
.name("vm_signal_handler".to_string())
.spawn(move || {
if !signal_handler_seccomp_filter.is_empty() {
if let Err(e) = apply_filter(&signal_handler_seccomp_filter)
.map_err(Error::ApplySeccompFilter)
{
error!("Error applying seccomp filter: {:?}", e);
exit_evt.write(1).ok();
return;
}
}
std::panic::catch_unwind(AssertUnwindSafe(|| {
Vm::signal_handler(signals, console);
}))
.map_err(|_| {
error!("vm signal_handler thread panicked");
exit_evt.write(1).ok()
})
.ok();
})
.map_err(Error::SignalHandlerSpawn)?,
);
}
Err(e) => error!("Signal not found {}", e),
}
Ok(())
}
// Creates ACPI tables
// In case of TDX being used, this is a no-op since the tables will be
// created and passed when populating the HOB.
@@ -1955,6 +2019,8 @@ impl Vm {
#[cfg(target_arch = "x86_64")]
let rsdp_addr = self.create_acpi_tables();
self.setup_signal_handler()?;
// Load kernel synchronously or if asynchronous then wait for load to
// finish.
let entry_point = self.entry_point()?;
@@ -2004,18 +2070,6 @@ impl Vm {
})
.transpose()?;
#[cfg(target_arch = "x86_64")]
// Note: For x86, always call this function before invoking start boot vcpus.
// Otherwise guest would fail to boot because we haven't created the
// userspace mappings to update the hypervisor about the memory mappings.
// These mappings must be created before we start the vCPU threads for
// the very first time.
self.memory_manager
.lock()
.unwrap()
.allocate_address_space()
.map_err(Error::MemoryManager)?;
#[cfg(feature = "tdx")]
if let Some(hob_address) = hob_address {
// With the HOB address extracted the vCPUs can have
@@ -2033,6 +2087,18 @@ impl Vm {
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
}
#[cfg(target_arch = "x86_64")]
// Note: For x86, always call this function before invoking start boot vcpus.
// Otherwise guest would fail to boot because we haven't created the
// userspace mappings to update the hypervisor about the memory mappings.
// These mappings must be created before we start the vCPU threads for
// the very first time.
self.memory_manager
.lock()
.unwrap()
.allocate_address_space()
.map_err(Error::MemoryManager)?;
self.cpu_manager
.lock()
.unwrap()
@@ -2067,6 +2133,8 @@ impl Vm {
.start_restored_vcpus()
.map_err(Error::CpuManager)?;
self.setup_signal_handler()?;
event!("vm", "restored");
Ok(())
}
@@ -2694,7 +2762,7 @@ mod tests {
// Check the transitions from Created
assert!(state.valid_transition(VmState::Created).is_err());
assert!(state.valid_transition(VmState::Running).is_ok());
assert!(state.valid_transition(VmState::Shutdown).is_ok());
assert!(state.valid_transition(VmState::Shutdown).is_err());
assert!(state.valid_transition(VmState::Paused).is_ok());
assert!(state.valid_transition(VmState::BreakPoint).is_ok());
}