Compare commits

..

15 Commits
v37.1 ... v35.1

Author SHA1 Message Date
Bo Chen
9c15de0118 build: Release v35.1 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-01-10 11:16:58 -08:00
Bo Chen
ca9e20c27a tests: Temporarily disable vhost_user_blk tests on aarch64
See: #5934

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 62db13ba0e)
2024-01-10 09:09:27 -08:00
Michael Zhao
028c3054ea scripts: Workaround random wget failures on AArch64
Random failures of downloading `cloud-hypervisor-static-aarch64` with
`wget` were seen. The commit applies a workaround to retry the download
for a few times.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
(cherry picked from commit f0c5592ba1)
2024-01-10 09:09:27 -08:00
Ravi kumar Veeramally
82f1dcea3c tests: Migrate docker container from ubuntu 20.04 to 22.04
The following tests have been temporarily disabled:

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

This patch has been tested with PR #6048.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
Tested-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 24f384d239)
2024-01-10 09:09:27 -08:00
Wei Liu
bd6c898b1d scripts: propagate RUSTFLAGS and TARGET_CC to test scripts
There is no need to set them in the test scripts while the main script
already has them.

The consolidates how things are done.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
(cherry picked from commit 8ba5682e3b)
2024-01-10 09:09:27 -08:00
Wei Liu
98c1e21d92 scripts: pass BUILD_TARGET directly to test scripts
There is no need to reconstruct it from within the scripts since the
main script already constructed it once.

Drop the previously useless setting of BUILD_TARGET from various
scripts. The value was always overwritten at a later point.

No functional change intended.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
(cherry picked from commit c7e51e51e5)
2024-01-10 09:09:27 -08:00
Wei Liu
7992997299 scripts: dev_cli.sh: respect preset RUSTFLAGS
Signed-off-by: Wei Liu <liuwe@microsoft.com>
(cherry picked from commit 9d42f48f49)
2024-01-10 09:09:27 -08:00
dom.song
a1627d295a tests: Update spdk code to support Ampere's new CPU
When performing integration testing on the Ampere One server, an error occurred when compiling spdk and not recognizing the CPU ID.
The latest spdk already contains fixes.

Signed-off-by: dom.song <dom.song@amperecomputing.com>
(cherry picked from commit 7f47a030e7)
2024-01-10 09:09:27 -08:00
Bo Chen
9278d565e2 mis: Fix clippy issues
Signed-off-by: Bo Chen <chen.bo@intel.com>
2024-01-10 09:09:27 -08:00
Yi Wang
f3c6f5c512 build: fix clippy complex closures issue
CI reports clippy errors:

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

Signed-off-by: Yi Wang <foxywang@tencent.com>
(cherry picked from commit 9c2d650cb8)
2024-01-10 09:09:27 -08:00
Bo Chen
7c3c2ee0d6 vmm: tdx: Error out early for TD migration
Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit e64b66054e)
2024-01-10 09:09:27 -08:00
Rui Chang
19e45650a6 vmm: add add-user-device support in cloud-hypervisor.yaml
The change is missed when add "add-user-device" support in
53b2e19934, use this commit to fix it.

Signed-off-by: Rui Chang <rui.chang@arm.com>
(cherry picked from commit 2b457584e0)
2024-01-10 09:09:27 -08:00
Thomas Barrett
c3a4289cbb devices: fix pv_panic alignment
Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
(cherry picked from commit 5f3ff3c44a)
2024-01-10 09:09:27 -08:00
Jianyong Wu
0886e79630 aarch64: fdt: Use more appropriate default value for topology
Now, default values for vcpu topology are 0s, that is not correct and may
lead to bug. Fix it by setting default value to 1s. Also add check in
case one or more of these values are zero.

Fixes: #5892
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
(cherry picked from commit 2434e76ee0)
2024-01-10 09:09:27 -08:00
Bo Chen
a40a0268bb vmm: tdx: Fix a deadlock while accessing vm_config
The lock to `vm_config` is held for accessing `cpus.kvm_hyperv` passing
as a reference to `arch::generate_common_cpuid()`, so acquiring the same
lock again while calling to the same function is a deadlock.

Fixes: 3793ffe888

Reported-by: Yi Wang <foxywang@tencent.com>
Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit aa6e83126c)
2024-01-10 09:09:27 -08:00
148 changed files with 3489 additions and 6934 deletions

View File

@@ -4,13 +4,12 @@ on:
paths: paths:
- '**/Cargo.toml' - '**/Cargo.toml'
- '**/Cargo.lock' - '**/Cargo.lock'
jobs: jobs:
security_audit: security_audit:
name: Audit name: Audit
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1 - uses: actions-rs/audit-check@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,11 +1,9 @@
name: Cloud Hypervisor Build name: Cloud Hypervisor Build
on: [pull_request, merge_group] on: [pull_request, create]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
if: github.event_name == 'pull_request'
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -15,13 +13,13 @@ jobs:
- stable - stable
- beta - beta
- nightly - nightly
- "1.70" - "1.64"
target: target:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -56,9 +54,6 @@ jobs:
- name: Build (sev_snp) - name: Build (sev_snp)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (igvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (mshv + kvm) - name: Build (mshv + kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks

View File

@@ -1,18 +1,16 @@
name: DCO name: DCO
on: [pull_request, merge_group] on:
pull_request:
jobs: jobs:
check: check:
name: DCO Check ("Signed-Off-By")
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Set up Python 3.x - name: Set up Python 3.x
uses: actions/setup-python@v1 uses: actions/setup-python@v1
with: with:
python-version: '3.x' python-version: '3.x'
- name: Check DCO - name: Check DCO
if: ${{ github.event_name == 'pull_request' }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |

View File

@@ -1,13 +1,11 @@
name: Cloud Hypervisor's Docker image update name: Cloud Hypervisor's Docker image update
on: on:
push: push:
branches: main branches: main
paths: resources/Dockerfile paths: resources/Dockerfile
pull_request: pull_request:
paths: resources/Dockerfile paths: resources/Dockerfile
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
@@ -18,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1

View File

@@ -1,11 +1,9 @@
name: Cloud Hypervisor Cargo Fuzz Build name: Cloud Hypervisor Cargo Fuzz Build
on: [pull_request, merge_group] on: [pull_request, create]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
if: github.event_name == 'pull_request'
name: Cargo Fuzz Build name: Cargo Fuzz Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -16,7 +14,7 @@ jobs:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Install Rust toolchain (${{ matrix.rust }}) - name: Install Rust toolchain (${{ matrix.rust }})
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:

View File

@@ -1,25 +0,0 @@
name: Commit messages check
on:
pull_request:
jobs:
gitlint:
name: Check commit messages
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade gitlint
- name: Lint git commit messages
run: |
gitlint --commits origin/$GITHUB_BASE_REF..

View File

@@ -1,4 +1,5 @@
name: Lint Dockerfile name: Lint Dockerfile
on: on:
push: push:
paths: paths:
@@ -13,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Lint Dockerfile - name: Lint Dockerfile
uses: hadolint/hadolint-action@master uses: hadolint/hadolint-action@master

View File

@@ -1,54 +0,0 @@
name: Cloud Hypervisor Tests (ARM64)
on: [pull_request, merge_group]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
timeout-minutes: 60
name: Tests (ARM64)
runs-on: focal-arm64
steps:
- name: Fix workspace permissions
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
- name: Code checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run unit tests (musl)
run: scripts/dev_cli.sh tests --unit --libc musl
- name: Load openvswitch module
run: sudo modprobe openvswitch
- name: Run integration tests (musl)
timeout-minutes: 30
run: scripts/dev_cli.sh tests --integration --libc musl
- name: Install Azure CLI
if: ${{ github.event_name != 'pull_request' }}
run: |
sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg
curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null
echo "deb [arch=arm64] https://packages.microsoft.com/repos/azure-cli/ focal main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
sudo apt update
sudo apt install -y azure-cli
- name: Download Windows image
if: ${{ github.event_name != 'pull_request' }}
shell: bash
run: |
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
IMG_PATH=$HOME/workloads/$IMG_BASENAME
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
pushd "$HOME/workloads"
if sha1sum "$IMG_BASENAME.sha1" --check; then
exit
fi
popd
mkdir -p "$HOME/workloads"
az storage blob download --container-name private-images --file "$IMG_GZ_PATH" --name "$IMG_GZ_BLOB_NAME" --connection-string "${{ secrets.CH_PRIVATE_IMAGES }}"
gzip -d $IMG_GZ_PATH
- name: Run Windows guest integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 30
run: scripts/dev_cli.sh tests --integration-windows --libc musl

View File

@@ -1,22 +0,0 @@
name: Cloud Hypervisor Tests (Metrics)
on:
push:
branches:
- main
jobs:
build:
name: Tests (Metrics)
runs-on: jammy-metrics
env:
METRICS_PUBLISH_KEY: ${{ secrets.METRICS_PUBLISH_KEY }}
steps:
- name: Code checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run metrics tests
timeout-minutes: 60
run: scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json
- name: Upload metrics report
run: 'curl -X PUT https://ch-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'

View File

@@ -1,28 +0,0 @@
name: Cloud Hypervisor Tests (Rate-Limiter)
on: [merge_group, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Tests (Rate-Limiter)
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-rate-limiter' }}
env:
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
steps:
- name: Fix workspace permissions
if: ${{ github.event_name != 'pull_request' }}
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run rate-limiter integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 10
run: scripts/dev_cli.sh tests --integration-rate-limiter
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' }}
run: echo "Skipping build for PR"

View File

@@ -1,32 +0,0 @@
name: Cloud Hypervisor Tests (SGX)
on: [merge_group, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Tests (SGX)
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-sgx' }}
env:
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
steps:
- name: Fix workspace permissions
if: ${{ github.event_name != 'pull_request' }}
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run SGX integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 10
run: scripts/dev_cli.sh tests --integration-sgx
- name: Run SGX integration tests for musl
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 10
run: scripts/dev_cli.sh tests --integration-sgx --libc musl
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' }}
run: echo "Skipping build for PR"

View File

@@ -1,32 +0,0 @@
name: Cloud Hypervisor Tests (VFIO)
on: [merge_group, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Tests (VFIO)
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-vfio' }}
env:
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
steps:
- name: Fix workspace permissions
if: ${{ github.event_name != 'pull_request' }}
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run VFIO integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 15
run: scripts/dev_cli.sh tests --integration-vfio
- name: Run VFIO integration tests for musl
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 15
run: scripts/dev_cli.sh tests --integration-vfio --libc musl
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' }}
run: echo "Skipping build for PR"

View File

@@ -1,50 +0,0 @@
name: Cloud Hypervisor Tests (Windows Guest)
on: [merge_group, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Tests (Windows Guest)
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'garm-jammy-16' }}
steps:
- name: Code checkout
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Docker
if: ${{ github.event_name != 'pull_request' }}
run: |
sudo apt-get update
sudo apt-get -y install ca-certificates curl gnupg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli
- name: Install Azure CLI
if: ${{ github.event_name != 'pull_request' }}
run: |
sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg
curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null
echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ jammy main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
sudo apt update
sudo apt install -y azure-cli
- name: Download Windows image
if: ${{ github.event_name != 'pull_request' }}
run: |
mkdir $HOME/workloads
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 "${{ secrets.CH_PRIVATE_IMAGES }}"
- name: Run Windows guest integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 15
run: scripts/dev_cli.sh tests --integration-windows
- name: Run Windows guest integration tests for musl
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 15
run: scripts/dev_cli.sh tests --integration-windows --libc musl
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' }}
run: echo "Skipping build for PR"

View File

@@ -1,52 +0,0 @@
name: Cloud Hypervisor Tests (x86-64)
on: [pull_request, merge_group]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
runner: ['garm-jammy', "garm-jammy-amd"]
libc: ["musl", 'gnu']
name: Tests (x86-64)
runs-on: ${{ github.event_name == 'pull_request' && !(matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') && 'ubuntu-latest' || format('{0}-16', matrix.runner) }}
steps:
- name: Code checkout
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Docker
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
run: |
sudo apt-get update
sudo apt-get -y install ca-certificates curl gnupg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli
- name: Prepare for VDPA
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
run: scripts/prepare_vdpa.sh
- name: Run unit tests
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
run: scripts/dev_cli.sh tests --unit --libc ${{ matrix.libc }}
- name: Load openvswitch module
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
run: sudo modprobe openvswitch
- name: Run integration tests
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
timeout-minutes: 40
run: scripts/dev_cli.sh tests --integration --libc ${{ matrix.libc }}
- name: Run live-migration integration tests
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
timeout-minutes: 20
run: scripts/dev_cli.sh tests --integration-live-migration --libc ${{ matrix.libc }}
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' && matrix.runner != 'garm-jammy' && matrix.libc != 'gnu' }}
run: echo "Skipping build for PR"

View File

@@ -1,14 +0,0 @@
name: Cloud Hypervisor OpenAPI Validation
on: [pull_request, merge_group]
jobs:
Validate:
runs-on: ubuntu-latest
container: openapitools/openapi-generator-cli
steps:
- uses: actions/checkout@v4
- name: Validate OpenAPI
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
/usr/local/bin/docker-entrypoint.sh validate -i vmm/src/api/openapi/cloud-hypervisor.yaml

View File

@@ -1,11 +1,9 @@
name: Cloud Hypervisor Quality Checks name: Cloud Hypervisor Quality Checks
on: [pull_request, merge_group] on: [pull_request, create]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
if: github.event_name == 'pull_request'
name: Quality (clippy, rustfmt) name: Quality (clippy, rustfmt)
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental }} continue-on-error: ${{ matrix.experimental }}
@@ -36,7 +34,7 @@ jobs:
experimental: true experimental: true
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -48,8 +46,8 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Bisectability Check (default features) - name: Debug Check (default features)
if: ${{ github.event_name == 'pull_request' && matrix.target == 'x86_64-unknown-linux-gnu' }} if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
run: | run: |
set -e set -e
commits=$(git rev-list origin/${{ github.base_ref }}..${{ github.sha }}) commits=$(git rev-list origin/${{ github.base_ref }}..${{ github.sha }})
@@ -111,14 +109,6 @@ jobs:
command: clippy command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (igvm)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (kvm + tdx) - name: Clippy (kvm + tdx)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }} if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -135,6 +125,6 @@ jobs:
name: Typos / Spellcheck name: Typos / Spellcheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
# Executes "typos ." # Executes "typos ."
- uses: crate-ci/typos@v1.16.11 - uses: crate-ci/typos@v1.16.11

View File

@@ -1,17 +1,14 @@
name: Cloud Hypervisor Release name: Cloud Hypervisor Release
on: [create, merge_group] on: [pull_request, create]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs: jobs:
release: release:
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'merge_group' if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'pull_request'
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Code checkout - name: Code checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Install musl-gcc - name: Install musl-gcc
run: sudo apt install -y musl-tools run: sudo apt install -y musl-tools
- name: Create release directory - name: Create release directory
@@ -19,29 +16,29 @@ jobs:
- name: Install Rust toolchain (x86_64-unknown-linux-gnu) - name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.70" toolchain: "1.67.1"
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl) - name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.70" toolchain: "1.67.1"
target: x86_64-unknown-linux-musl target: x86_64-unknown-linux-musl
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.70" toolchain: "1.67.1"
command: build command: build
args: --all --release --features mshv --target=x86_64-unknown-linux-gnu args: --all --release --features mshv --target=x86_64-unknown-linux-gnu
- name: Static Build - name: Static Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.70" toolchain: "1.67.1"
command: build command: build
args: --all --release --features mshv --target=x86_64-unknown-linux-musl args: --all --release --features mshv --target=x86_64-unknown-linux-musl
- name: Install Rust toolchain (aarch64-unknown-linux-musl) - name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.70" toolchain: "1.67.1"
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
override: true override: true
- name: Create Release - name: Create Release

View File

@@ -1,15 +0,0 @@
[general]
extra-path=scripts/gitlint/rules.py
regex-style-search=true
[ignore-by-author-name]
regex=dependabot
ignore=all
# default 72
[title-max-length]
line-length=72
# default 80
[body-max-line-length]
line-length=72

831
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "37.1.0" version = "35.1.0"
authors = ["The Cloud Hypervisor Authors"] authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
default-run = "cloud-hypervisor" default-run = "cloud-hypervisor"
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# a.) A dependency requires it, # a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old, # b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update. # c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.70" rust-version = "1.64"
[profile.release] [profile.release]
lto = true lto = true
@@ -31,29 +31,30 @@ debug = true
[dependencies] [dependencies]
anyhow = "1.0.75" anyhow = "1.0.75"
api_client = { path = "api_client" } api_client = { path = "api_client" }
clap = { version = "4.4.7", features = ["string"] } argh = "0.1.9"
dhat = { version = "0.3.2", optional = true } dhat = { version = "0.3.2", optional = true }
epoll = "4.3.3" epoll = "4.3.3"
event_monitor = { path = "event_monitor" } event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" } hypervisor = { path = "hypervisor" }
libc = "0.2.147" libc = "0.2.147"
log = { version = "0.4.20", features = ["std"] } log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" } option_parser = { path = "option_parser" }
seccompiler = "0.4.0" seccompiler = "0.3.0"
serde_json = "1.0.107" serde_json = "1.0.107"
signal-hook = "0.3.17" signal-hook = "0.3.17"
thiserror = "1.0.40" thiserror = "1.0.40"
tpm = { path = "tpm"} tpm = { path = "tpm"}
tracer = { path = "tracer" } tracer = { path = "tracer" }
vmm = { path = "vmm" } vmm = { path = "vmm" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"
vm-memory = "0.14.0" vm-memory = "0.12.2"
zbus = { version = "3.11.1", optional = true } zbus = { version = "3.11.1", optional = true }
# List of patched crates # List of patched crates
[patch.crates-io] [patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x" } kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" } 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] [dev-dependencies]
dirs = "5.0.0" dirs = "5.0.0"
@@ -63,18 +64,15 @@ serde_json = "1.0.107"
test_infra = { path = "test_infra" } test_infra = { path = "test_infra" }
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
# Please adjust `vmm::feature_list()` accordingly when changing the
# feature list below
[features] [features]
default = ["kvm", "io_uring"] default = ["kvm", "io_uring"]
dbus_api = ["zbus", "vmm/dbus_api"] dbus_api = ["zbus", "vmm/dbus_api"]
dhat-heap = ["dhat"] # For heap profiling dhat-heap = ["dhat"] # For heap profiling
guest_debug = ["vmm/guest_debug"] guest_debug = ["vmm/guest_debug"]
igvm = ["vmm/igvm", "mshv"]
io_uring = ["vmm/io_uring"] io_uring = ["vmm/io_uring"]
kvm = ["vmm/kvm"] kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"] mshv = ["vmm/mshv"]
sev_snp = ["igvm", "vmm/sev_snp", "mshv"] sev_snp = ["vmm/sev_snp", "mshv"]
tdx = ["vmm/tdx"] tdx = ["vmm/tdx"]
tracing = ["vmm/tracing", "tracer/tracing"] tracing = ["vmm/tracing", "tracer/tracing"]

509
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,509 @@
def runWorkers = true
pipeline {
agent none
options {
timeout(time: 4, unit: 'HOURS')
}
stages {
stage('Early checks') {
agent { node { label 'built-in' } }
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Check if worker build can be skipped') {
when {
expression {
return skipWorkerBuild()
}
}
steps {
script {
runWorkers = false
echo 'No changes requiring a build'
}
}
}
stage('Check for RFC/WIP builds') {
when {
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
beforeAgent true
}
steps {
error('Failing as this is marked as a WIP or RFC PR.')
}
}
stage('Cancel older builds') {
when { not { branch 'main' } }
steps {
cancelPreviousBuilds()
}
}
}
}
stage('Build') {
parallel {
stage('Worker build') {
agent { node { label 'jammy' } }
when {
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Prepare environment') {
steps {
sh 'scripts/prepare_vdpa.sh'
}
}
stage('Run OpenAPI tests') {
steps {
sh 'scripts/run_openapi_tests.sh'
}
}
stage('Run unit tests') {
steps {
sh 'scripts/dev_cli.sh tests --unit'
}
}
stage('Run integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration'
}
}
stage('Run live-migration integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration'
}
}
stage('Run unit tests for musl') {
steps {
sh 'scripts/dev_cli.sh tests --unit --libc musl'
}
}
stage('Run integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration --libc musl'
}
}
stage('Run live-migration integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl'
}
}
}
}
stage('Worker build - AMD') {
agent { node { label 'jammy-amd' } }
when {
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Prepare environment') {
steps {
sh 'scripts/prepare_vdpa.sh'
}
}
stage('Run integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration -- -- --skip common_parallel::test_vfio'
}
}
stage('Run live-migration integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration'
}
}
stage('Run integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration --libc musl -- -- --skip common_parallel::test_vfio'
}
}
stage('Run live-migration integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl'
}
}
}
}
stage('AArch64 worker build') {
agent { node { label 'bionic-arm64' } }
when {
beforeAgent true
expression {
return runWorkers
}
}
environment {
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run unit tests') {
steps {
sh 'scripts/dev_cli.sh tests --unit --libc musl'
}
}
stage('Run integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration --libc musl'
}
}
stage('Install azure-cli') {
steps {
installAzureCli('focal', 'arm64')
}
}
stage('Download Windows image') {
steps {
sh '''#!/bin/bash -x
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
IMG_PATH=$HOME/workloads/$IMG_BASENAME
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
pushd "$HOME/workloads"
if sha1sum "$IMG_BASENAME.sha1" --check; then
exit
fi
popd
mkdir -p "$HOME/workloads"
az storage blob download \
--container-name private-images \
--file "$IMG_GZ_PATH" \
--name "$IMG_GZ_BLOB_NAME" \
--connection-string "$AZURE_CONNECTION_STRING"
gzip -d $IMG_GZ_PATH
'''
}
}
stage('Run Windows guest integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
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 {
branch 'main'
beforeAgent true
expression {
return runWorkers
}
}
environment {
METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run metrics tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
}
}
stage('Upload metrics report') {
steps {
sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
}
}
}
}
stage('Worker build - Rate Limiter') {
agent { node { label 'focal-metrics' } }
when {
branch 'main'
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run rate-limiter integration tests') {
options {
timeout(time: 10, unit: 'MINUTES')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-rate-limiter'
}
}
}
}
stage('Worker build - SGX') {
agent { node { label 'jammy-sgx' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run SGX integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx'
}
}
stage('Run SGX integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
stage('Worker build - VFIO') {
agent { node { label 'jammy-vfio' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run VFIO integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-vfio'
}
}
stage('Run VFIO integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-vfio --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
}
}
}
post {
regression {
script {
if (env.BRANCH_NAME == 'main') {
slackSend(color: '#ff0000', message: '"main" branch build is now failing', channel: '#jenkins-ci')
}
}
}
fixed {
script {
if (env.BRANCH_NAME == 'main') {
slackSend(color: '#00ff00', message: '"main" branch build is now fixed', channel: '#jenkins-ci')
}
}
}
}
}
def cancelPreviousBuilds() {
// Check for other instances of this particular build, cancel any that are older than the current one
def jobName = env.JOB_NAME
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
def currentJob = Jenkins.instance.getItemByFullName(jobName)
// Loop through all instances of this particular job/branch
for (def build : currentJob.builds) {
if (build.isBuilding() && (build.number.toInteger() < currentBuildNumber)) {
echo "Older build still queued. Sending kill signal to build number: ${build.number}"
build.doStop()
}
}
}
def installAzureCli(distro, arch) {
sh 'sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg'
sh 'curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null'
sh "echo \"deb [arch=${arch}] https://packages.microsoft.com/repos/azure-cli/ ${distro} main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
sh 'sudo apt update'
sh 'sudo apt install -y azure-cli'
}
def boolean skipWorkerBuild() {
if (env.CHANGE_TARGET == null) {
return false
}
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
) != 0) {
return true
}
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz/'"
) != 0) {
return true
}
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E '.github/'"
) != 0) {
return true
}
return false
}

View File

@@ -150,7 +150,7 @@ $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
$ ./create-cloud-init.sh $ ./create-cloud-init.sh
$ ./cloud-hypervisor \ $ ./cloud-hypervisor \
--kernel ./hypervisor-fw \ --kernel ./hypervisor-fw \
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \ --disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
--cpus boot=4 \ --cpus boot=4 \
--memory size=1024M \ --memory size=1024M \
--net "tap=,mac=,ip=,mask=" --net "tap=,mac=,ip=,mask="
@@ -163,7 +163,7 @@ GRUB) is required then it necessary to switch to the serial console instead of
```shell ```shell
$ ./cloud-hypervisor \ $ ./cloud-hypervisor \
--kernel ./hypervisor-fw \ --kernel ./hypervisor-fw \
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \ --disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
--cpus boot=4 \ --cpus boot=4 \
--memory size=1024M \ --memory size=1024M \
--net "tap=,mac=,ip=,mask=" \ --net "tap=,mac=,ip=,mask=" \
@@ -225,7 +225,7 @@ $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
$ ./create-cloud-init.sh $ ./create-cloud-init.sh
$ ./cloud-hypervisor \ $ ./cloud-hypervisor \
--kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \ --kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \ --disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
--cmdline "console=hvc0 root=/dev/vda1 rw" \ --cmdline "console=hvc0 root=/dev/vda1 rw" \
--cpus boot=4 \ --cpus boot=4 \
--memory size=1024M \ --memory size=1024M \
@@ -239,7 +239,7 @@ $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
$ ./create-cloud-init.sh $ ./create-cloud-init.sh
$ ./cloud-hypervisor \ $ ./cloud-hypervisor \
--kernel ./linux-cloud-hypervisor/arch/arm64/boot/Image \ --kernel ./linux-cloud-hypervisor/arch/arm64/boot/Image \
--disk path=focal-server-cloudimg-arm64.raw path=/tmp/ubuntu-cloudinit.img \ --disk path=focal-server-cloudimg-arm64.raw --disk path=/tmp/ubuntu-cloudinit.img \
--cmdline "console=hvc0 root=/dev/vda1 rw" \ --cmdline "console=hvc0 root=/dev/vda1 rw" \
--cpus boot=4 \ --cpus boot=4 \
--memory size=1024M \ --memory size=1024M \

View File

@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"

View File

@@ -14,16 +14,16 @@ anyhow = "1.0.75"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.147" libc = "0.2.147"
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] } linux-loader = { version = "0.9.1", features = ["elf", "bzimage", "pe"] }
log = "0.4.20" log = "0.4.17"
serde = { version = "1.0.168", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
thiserror = "1.0.40" thiserror = "1.0.40"
uuid = "1.3.4" uuid = "1.3.4"
versionize = "0.2.0" versionize = "0.1.10"
versionize_derive = "0.1.6" versionize_derive = "0.1.4"
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-bitmap"] } vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] } vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
[target.'cfg(target_arch = "aarch64")'.dependencies] [target.'cfg(target_arch = "aarch64")'.dependencies]
fdt_parser = { version = "0.1.4", package = "fdt" } fdt_parser = { version = "0.1.4", package = "fdt" }

View File

@@ -1,9 +1,8 @@
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved. // Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::os::fd::AsFd;
use std::result; use std::result;
use vm_memory::{GuestAddress, GuestMemory}; use vm_memory::{Bytes, GuestAddress, GuestMemory};
/// Errors thrown while loading UEFI binary /// Errors thrown while loading UEFI binary
#[derive(Debug)] #[derive(Debug)]
@@ -25,7 +24,7 @@ pub fn load_uefi<F, M: GuestMemory>(
uefi_image: &mut F, uefi_image: &mut F,
) -> Result<()> ) -> Result<()>
where where
F: Read + Seek + AsFd, F: Read + Seek,
{ {
let uefi_size = uefi_image let uefi_size = uefi_image
.seek(SeekFrom::End(0)) .seek(SeekFrom::End(0))
@@ -37,6 +36,6 @@ where
} }
uefi_image.rewind().map_err(|_| Error::SeekUefiStart)?; uefi_image.rewind().map_err(|_| Error::SeekUefiStart)?;
guest_mem guest_mem
.read_exact_volatile_from(guest_addr, &mut uefi_image.as_fd(), uefi_size) .read_exact_from(guest_addr, uefi_image, uefi_size)
.map_err(|_| Error::ReadUefiImage) .map_err(|_| Error::ReadUefiImage)
} }

View File

@@ -91,9 +91,8 @@ pub mod x86_64;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use x86_64::{ pub use x86_64::{
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid, arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
generate_ram_ranges, get_host_cpu_phys_bits, initramfs_load_addr, layout, get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry, layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG,
EntryPoint, _NSIG,
}; };
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`. /// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
@@ -109,7 +108,6 @@ pub struct NumaNode {
pub memory_regions: Vec<Arc<GuestRegionMmap>>, pub memory_regions: Vec<Arc<GuestRegionMmap>>,
pub hotplug_regions: Vec<Arc<GuestRegionMmap>>, pub hotplug_regions: Vec<Arc<GuestRegionMmap>>,
pub cpus: Vec<u8>, pub cpus: Vec<u8>,
pub pci_segments: Vec<u16>,
pub distances: BTreeMap<u32, u8>, pub distances: BTreeMap<u32, u8>,
pub memory_zones: Vec<String>, pub memory_zones: Vec<String>,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]

View File

@@ -17,13 +17,14 @@ use crate::InitramfsConfig;
use crate::RegionType; use crate::RegionType;
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX}; use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError}; use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
use linux_loader::loader::bootparam::boot_params;
use linux_loader::loader::elf::start_info::{ use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
}; };
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::mem; use std::mem;
use vm_memory::{ use vm_memory::{
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
GuestMemoryRegion, GuestUsize, GuestMemoryRegion, GuestUsize,
}; };
mod smbios; mod smbios;
@@ -36,9 +37,6 @@ const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit. const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit. const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX
const AMX_BF16: u8 = 22; // AMX tile computation on bfloat16 numbers
const AMX_TILE: u8 = 24; // AMX tile load/store instructions
const AMX_INT8: u8 = 25; // AMX tile computation on 8-bit integers
// KVM feature bits // KVM feature bits
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
@@ -115,14 +113,37 @@ impl SgxEpcRegion {
} }
} }
pub struct CpuidConfig { // This is a workaround to the Rust enforcement specifying that any implementation of a foreign
pub sgx_epc_sections: Option<Vec<SgxEpcSection>>, // trait (in this case `DataInit`) where:
pub phys_bits: u8, // * the type that is implementing the trait is foreign or
pub kvm_hyperv: bool, // * all of the parameters being passed to the trait (if there are any) are also foreign
#[cfg(feature = "tdx")] // is prohibited.
pub tdx: bool, #[derive(Copy, Clone, Default)]
pub amx: bool, struct StartInfoWrapper(hvm_start_info);
}
#[derive(Copy, Clone, Default)]
struct MemmapTableEntryWrapper(hvm_memmap_table_entry);
#[derive(Copy, Clone, Default)]
struct ModlistEntryWrapper(hvm_modlist_entry);
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for StartInfoWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for MemmapTableEntryWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for ModlistEntryWrapper {}
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
// trait (in this case `DataInit`) where:
// * the type that is implementing the trait is foreign or
// * all of the parameters being passed to the trait (if there are any) are also foreign
// is prohibited.
#[derive(Copy, Clone, Default)]
struct BootParamsWrapper(boot_params);
// SAFETY: BootParamsWrap is a wrapper over `boot_params` (a series of ints).
unsafe impl ByteValued for BootParamsWrapper {}
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@@ -188,26 +209,6 @@ impl From<Error> for super::Error {
} }
} }
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
if let Some(t) = topology {
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
let core_mask_width = u8::BITS - (t.1 - 1).leading_zeros();
let die_mask_width = u8::BITS - (t.2 - 1).leading_zeros();
let thread_id = cpu_id % (t.0 as u32);
let core_id = cpu_id / (t.0 as u32) % (t.1 as u32);
let die_id = cpu_id / ((t.0 * t.1) as u32) % (t.2 as u32);
let socket_id = cpu_id / ((t.0 * t.1 * t.2) as u32);
return thread_id
| (core_id << thread_mask_width)
| (die_id << (thread_mask_width + core_mask_width))
| (socket_id << (thread_mask_width + core_mask_width + die_mask_width));
}
cpu_id
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum CpuidReg { pub enum CpuidReg {
EAX, EAX,
@@ -227,26 +228,6 @@ pub struct CpuidPatch {
} }
impl CpuidPatch { impl CpuidPatch {
pub fn get_cpuid_reg(
cpuid: &[CpuIdEntry],
function: u32,
index: Option<u32>,
reg: CpuidReg,
) -> Option<u32> {
for entry in cpuid.iter() {
if entry.function == function && (index.is_none() || index.unwrap() == entry.index) {
return match reg {
CpuidReg::EAX => Some(entry.eax),
CpuidReg::EBX => Some(entry.ebx),
CpuidReg::ECX => Some(entry.ecx),
CpuidReg::EDX => Some(entry.edx),
};
}
}
None
}
pub fn set_cpuid_reg( pub fn set_cpuid_reg(
cpuid: &mut Vec<CpuIdEntry>, cpuid: &mut Vec<CpuIdEntry>,
function: u32, function: u32,
@@ -571,7 +552,11 @@ impl CpuidFeatureEntry {
pub fn generate_common_cpuid( pub fn generate_common_cpuid(
hypervisor: &Arc<dyn hypervisor::Hypervisor>, hypervisor: &Arc<dyn hypervisor::Hypervisor>,
config: &CpuidConfig, topology: Option<(u8, u8, u8)>,
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
phys_bits: u8,
kvm_hyperv: bool,
#[cfg(feature = "tdx")] tdx_enabled: bool,
) -> super::Result<Vec<CpuIdEntry>> { ) -> super::Result<Vec<CpuIdEntry>> {
// SAFETY: cpuid called with valid leaves // SAFETY: cpuid called with valid leaves
if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT { if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT {
@@ -589,10 +574,7 @@ pub fn generate_common_cpuid(
); );
} }
info!( info!("Generating guest CPUID for with physical address size: {phys_bits}");
"Generating guest CPUID for with physical address size: {}",
config.phys_bits
);
let cpuid_patches = vec![ let cpuid_patches = vec![
// Patch tsc deadline timer bit // Patch tsc deadline timer bit
CpuidPatch { CpuidPatch {
@@ -633,12 +615,16 @@ pub fn generate_common_cpuid(
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches); CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
if let Some(sgx_epc_sections) = &config.sgx_epc_sections { if let Some(t) = topology {
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2);
}
if let Some(sgx_epc_sections) = sgx_epc_sections {
update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?; update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?;
} }
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
let tdx_capabilities = if config.tdx { let tdx_capabilities = if tdx_enabled {
let caps = hypervisor let caps = hypervisor
.tdx_capabilities() .tdx_capabilities()
.map_err(Error::TdxCapabilities)?; .map_err(Error::TdxCapabilities)?;
@@ -651,12 +637,6 @@ pub fn generate_common_cpuid(
// Update some existing CPUID // Update some existing CPUID
for entry in cpuid.as_mut_slice().iter_mut() { for entry in cpuid.as_mut_slice().iter_mut() {
match entry.function { match entry.function {
// Clear AMX related bits if the AMX feature is not enabled
0x7 => {
if !config.amx && entry.index == 0 {
entry.edx &= !(1 << AMX_BF16 | 1 << AMX_TILE | 1 << AMX_INT8)
}
}
0xd => 0xd =>
{ {
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
@@ -692,12 +672,12 @@ pub fn generate_common_cpuid(
} }
// Set CPU physical bits // Set CPU physical bits
0x8000_0008 => { 0x8000_0008 => {
entry.eax = (entry.eax & 0xffff_ff00) | (config.phys_bits as u32 & 0xff); entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
} }
0x4000_0001 => { 0x4000_0001 => {
// These features are not supported by TDX // These features are not supported by TDX
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
if config.tdx { if tdx_enabled {
entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE2_BIT | 1 << KVM_FEATURE_CLOCKSOURCE2_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT | 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT
@@ -725,7 +705,7 @@ pub fn generate_common_cpuid(
}); });
} }
if config.kvm_hyperv { if kvm_hyperv {
// Remove conflicting entries // Remove conflicting entries
cpuid.retain(|c| c.function != 0x4000_0000); cpuid.retain(|c| c.function != 0x4000_0000);
cpuid.retain(|c| c.function != 0x4000_0001); cpuid.retain(|c| c.function != 0x4000_0001);
@@ -781,30 +761,19 @@ pub fn configure_vcpu(
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>, boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
cpuid: Vec<CpuIdEntry>, cpuid: Vec<CpuIdEntry>,
kvm_hyperv: bool, kvm_hyperv: bool,
cpu_vendor: CpuVendor,
topology: Option<(u8, u8, u8)>,
) -> super::Result<()> { ) -> super::Result<()> {
let x2apic_id = get_x2apic_id(id as u32, topology);
// Per vCPU CPUID changes; common are handled via generate_common_cpuid() // Per vCPU CPUID changes; common are handled via generate_common_cpuid()
let mut cpuid = cpuid; let mut cpuid = cpuid;
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, x2apic_id); CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, x2apic_id); CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
if matches!(cpu_vendor, CpuVendor::AMD) {
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x8000_001e, Some(0), CpuidReg::EAX, x2apic_id);
}
// Set ApicId in cpuid for each vcpu // Set ApicId in cpuid for each vcpu
// SAFETY: get host cpuid when eax=1 // SAFETY: get host cpuid when eax=1
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx; let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
cpu_ebx &= 0xffffff; cpu_ebx &= 0xffffff;
cpu_ebx |= x2apic_id << 24; cpu_ebx |= (id as u32) << 24;
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx); CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
if let Some(t) = topology {
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2, cpu_vendor, id);
}
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation // The TSC frequency CPUID leaf should not be included when running with HyperV emulation
if !kvm_hyperv { if !kvm_hyperv {
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? { if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
@@ -899,7 +868,6 @@ pub fn configure_system(
serial_number: Option<&str>, serial_number: Option<&str>,
uuid: Option<&str>, uuid: Option<&str>,
oem_strings: Option<&[&str]>, oem_strings: Option<&[&str]>,
topology: Option<(u8, u8, u8)>,
) -> super::Result<()> { ) -> super::Result<()> {
// Write EBDA address to location where ACPICA expects to find it // Write EBDA address to location where ACPICA expects to find it
guest_mem guest_mem
@@ -912,7 +880,7 @@ pub fn configure_system(
// Place the MP table after the SMIOS table aligned to 16 bytes // Place the MP table after the SMIOS table aligned to 16 bytes
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size); let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
let offset = GuestAddress((offset.0 + 16) & !0xf); let offset = GuestAddress((offset.0 + 16) & !0xf);
mptable::setup_mptable(offset, guest_mem, _num_cpus, topology).map_err(Error::MpTableSetup)?; mptable::setup_mptable(offset, guest_mem, _num_cpus).map_err(Error::MpTableSetup)?;
// Check that the RAM is not smaller than the RSDP start address // Check that the RAM is not smaller than the RSDP start address
if let Some(rsdp_addr) = rsdp_addr { if let Some(rsdp_addr) = rsdp_addr {
@@ -930,16 +898,52 @@ pub fn configure_system(
) )
} }
type RamRange = (u64, u64); fn configure_pvh(
/// Returns usable physical memory ranges for the guest
/// These should be used to create e820_RAM memory maps
///
/// There are up to two usable physical memory ranges,
/// divided by the gap at the end of 32bit address space.
pub fn generate_ram_ranges(
guest_mem: &GuestMemoryMmap, guest_mem: &GuestMemoryMmap,
) -> super::Result<(RamRange, Option<RamRange>)> { cmdline_addr: GuestAddress,
initramfs: &Option<InitramfsConfig>,
rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>,
) -> super::Result<()> {
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
let mut start_info: StartInfoWrapper = StartInfoWrapper(hvm_start_info::default());
start_info.0.magic = XEN_HVM_START_MAGIC_VALUE;
start_info.0.version = 1; // pvh has version 1
start_info.0.nr_modules = 0;
start_info.0.cmdline_paddr = cmdline_addr.raw_value();
start_info.0.memmap_paddr = layout::MEMMAP_START.raw_value();
if let Some(rsdp_addr) = rsdp_addr {
start_info.0.rsdp_paddr = rsdp_addr.0;
}
if let Some(initramfs_config) = initramfs {
// The initramfs has been written to guest memory already, here we just need to
// create the module structure that describes it.
let ramdisk_mod: ModlistEntryWrapper = ModlistEntryWrapper(hvm_modlist_entry {
paddr: initramfs_config.address.raw_value(),
size: initramfs_config.size as u64,
..Default::default()
});
start_info.0.nr_modules += 1;
start_info.0.modlist_paddr = layout::MODLIST_START.raw_value();
// Write the modlist struct to guest memory.
guest_mem
.write_obj(ramdisk_mod, layout::MODLIST_START)
.map_err(super::Error::ModlistSetup)?;
}
// Vector to hold the memory maps which needs to be written to guest memory
// at MEMMAP_START after all of the mappings are recorded.
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
// 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. // Merge continuous memory regions into one region.
// Note: memory regions from "GuestMemory" are sorted and non-zero sized. // Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = { let ram_regions = {
@@ -974,14 +978,14 @@ pub fn generate_ram_ranges(
if ram_regions.len() > 2 { if ram_regions.len() > 2 {
error!( error!(
"There should be up to two usable physical memory ranges, devidided by the "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)." gap at the end of 32bit address space (e.g. between 3G and 4G)."
); );
return Err(super::Error::MemmapTableSetup); return Err(super::Error::MemmapTableSetup);
} }
// Generate the first usable physical memory range before the gap // Create the memory map entry for memory region before the gap
let first_ram_range = { {
let (first_region_start, first_region_end) = let (first_region_start, first_region_end) =
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?; ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
let high_ram_start = layout::HIGH_RAM_START.raw_value(); let high_ram_start = layout::HIGH_RAM_START.raw_value();
@@ -1001,17 +1005,20 @@ pub fn generate_ram_ranges(
} }
info!( info!(
"first usable physical memory range, start: 0x{:08x}, end: 0x{:08x}", "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
high_ram_start, first_region_end high_ram_start, first_region_end
); );
(high_ram_start, *first_region_end) add_memmap_entry(
}; &mut memmap,
high_ram_start,
first_region_end - high_ram_start,
E820_RAM,
);
}
// Generate the second usable physical memory range after the gap if any // Create the memory map entry for memory region after the gap if any
let second_ram_range = if let Some((second_region_start, second_region_end)) = if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
ram_regions.get(1)
{
let ram_64bit_start = layout::RAM_64BIT_START.raw_value(); let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
if second_region_start != &ram_64bit_start { if second_region_start != &ram_64bit_start {
@@ -1023,91 +1030,14 @@ pub fn generate_ram_ranges(
return Err(super::Error::MemmapTableSetup); return Err(super::Error::MemmapTableSetup);
} }
info!(
"Second usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
ram_64bit_start, second_region_end
);
Some((ram_64bit_start, *second_region_end))
} else {
None
};
Ok((first_ram_range, second_ram_range))
}
fn configure_pvh(
guest_mem: &GuestMemoryMmap,
cmdline_addr: GuestAddress,
initramfs: &Option<InitramfsConfig>,
rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>,
) -> super::Result<()> {
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
let mut start_info = hvm_start_info {
magic: XEN_HVM_START_MAGIC_VALUE,
version: 1, // pvh has version 1
nr_modules: 0,
cmdline_paddr: cmdline_addr.raw_value(),
memmap_paddr: layout::MEMMAP_START.raw_value(),
..Default::default()
};
if let Some(rsdp_addr) = rsdp_addr {
start_info.rsdp_paddr = rsdp_addr.0;
}
if let Some(initramfs_config) = initramfs {
// The initramfs has been written to guest memory already, here we just need to
// create the module structure that describes it.
let ramdisk_mod = hvm_modlist_entry {
paddr: initramfs_config.address.raw_value(),
size: initramfs_config.size as u64,
..Default::default()
};
start_info.nr_modules += 1;
start_info.modlist_paddr = layout::MODLIST_START.raw_value();
// Write the modlist struct to guest memory.
guest_mem
.write_obj(ramdisk_mod, layout::MODLIST_START)
.map_err(super::Error::ModlistSetup)?;
}
// Vector to hold the memory maps which needs to be written to guest memory
// at MEMMAP_START after all of the mappings are recorded.
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
// Create the memory map entries.
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
// Get usable physical memory ranges
let (first_ram_range, second_ram_range) = generate_ram_ranges(guest_mem)?;
// Create e820 memory map entry before the gap
info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
first_ram_range.0, first_ram_range.1
);
add_memmap_entry(
&mut memmap,
first_ram_range.0,
first_ram_range.1 - first_ram_range.0,
E820_RAM,
);
// Create e820 memory map after the gap if any
if let Some(second_ram_range) = second_ram_range {
info!( info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}", "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
second_ram_range.0, second_ram_range.1 ram_64bit_start, second_region_end
); );
add_memmap_entry( add_memmap_entry(
&mut memmap, &mut memmap,
second_ram_range.0, ram_64bit_start,
second_ram_range.1 - second_ram_range.0, second_region_end - ram_64bit_start,
E820_RAM, E820_RAM,
); );
} }
@@ -1128,7 +1058,7 @@ fn configure_pvh(
); );
} }
start_info.memmap_entries = memmap.len() as u32; start_info.0.memmap_entries = memmap.len() as u32;
// Copy the vector with the memmap table to the MEMMAP_START address // Copy the vector with the memmap table to the MEMMAP_START address
// which is already saved in the memmap_paddr field of hvm_start_info struct. // which is already saved in the memmap_paddr field of hvm_start_info struct.
@@ -1137,14 +1067,17 @@ fn configure_pvh(
guest_mem guest_mem
.checked_offset( .checked_offset(
memmap_start_addr, memmap_start_addr,
mem::size_of::<hvm_memmap_table_entry>() * start_info.memmap_entries as usize, mem::size_of::<hvm_memmap_table_entry>() * start_info.0.memmap_entries as usize,
) )
.ok_or(super::Error::MemmapTablePastRamEnd)?; .ok_or(super::Error::MemmapTablePastRamEnd)?;
// For every entry in the memmap vector, write it to guest memory. // For every entry in the memmap vector, create a MemmapTableEntryWrapper
// and write it to guest memory.
for memmap_entry in memmap { for memmap_entry in memmap {
let map_entry_wrapper: MemmapTableEntryWrapper = MemmapTableEntryWrapper(memmap_entry);
guest_mem guest_mem
.write_obj(memmap_entry, memmap_start_addr) .write_obj(map_entry_wrapper, memmap_start_addr)
.map_err(|_| super::Error::MemmapTableSetup)?; .map_err(|_| super::Error::MemmapTableSetup)?;
memmap_start_addr = memmap_start_addr =
memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64); memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64);
@@ -1227,27 +1160,11 @@ fn update_cpuid_topology(
threads_per_core: u8, threads_per_core: u8,
cores_per_die: u8, cores_per_die: u8,
dies_per_package: u8, dies_per_package: u8,
cpu_vendor: CpuVendor,
id: u8,
) { ) {
let x2apic_id = get_x2apic_id(
id as u32,
Some((threads_per_core, cores_per_die, dies_per_package)),
);
let thread_width = 8 - (threads_per_core - 1).leading_zeros(); let thread_width = 8 - (threads_per_core - 1).leading_zeros();
let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width; let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width;
let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width; let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width;
let mut cpu_ebx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX).unwrap_or(0);
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
& 0xff << 16;
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
let mut cpu_edx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX).unwrap_or(0);
cpu_edx |= 1 << 28;
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX, cpu_edx);
// CPU Topology leaf 0xb // CPU Topology leaf 0xb
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width); CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width);
CpuidPatch::set_cpuid_reg( CpuidPatch::set_cpuid_reg(
@@ -1299,72 +1216,13 @@ fn update_cpuid_topology(
u32::from(dies_per_package * cores_per_die * threads_per_core), u32::from(dies_per_package * cores_per_die * threads_per_core),
); );
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::ECX, 5 << 8); CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::ECX, 5 << 8);
if matches!(cpu_vendor, CpuVendor::AMD) {
CpuidPatch::set_cpuid_reg(
cpuid,
0x8000_001e,
Some(0),
CpuidReg::EBX,
((threads_per_core as u32 - 1) << 8) | (x2apic_id & 0xff),
);
CpuidPatch::set_cpuid_reg(
cpuid,
0x8000_001e,
Some(0),
CpuidReg::ECX,
((dies_per_package as u32 - 1) << 8) | (thread_width + die_width) & 0xff,
);
CpuidPatch::set_cpuid_reg(cpuid, 0x8000_001e, Some(0), CpuidReg::EDX, 0);
if cores_per_die * threads_per_core > 1 {
let ecx =
CpuidPatch::get_cpuid_reg(cpuid, 0x8000_0001, Some(0), CpuidReg::ECX).unwrap_or(0);
CpuidPatch::set_cpuid_reg(
cpuid,
0x8000_0001,
Some(0),
CpuidReg::ECX,
ecx | (1u32 << 1) | (1u32 << 22),
);
CpuidPatch::set_cpuid_reg(
cpuid,
0x0000_0001,
Some(0),
CpuidReg::EBX,
(x2apic_id << 24) | (8 << 8) | (((cores_per_die * threads_per_core) as u32) << 16),
);
let cpuid_patches = vec![
// Patch tsc deadline timer bit
CpuidPatch {
function: 1,
index: 0,
flags_bit: None,
eax_bit: None,
ebx_bit: None,
ecx_bit: None,
edx_bit: Some(28),
},
];
CpuidPatch::patch_cpuid(cpuid, cpuid_patches);
CpuidPatch::set_cpuid_reg(
cpuid,
0x8000_0008,
Some(0),
CpuidReg::ECX,
((thread_width + core_width + die_width) << 12)
| ((cores_per_die * threads_per_core) - 1) as u32,
);
} else {
CpuidPatch::set_cpuid_reg(cpuid, 0x8000_0008, Some(0), CpuidReg::ECX, 0u32);
}
}
} }
// The goal is to update the CPUID sub-leaves to reflect the number of EPC // The goal is to update the CPUID sub-leaves to reflect the number of EPC
// sections exposed to the guest. // sections exposed to the guest.
fn update_cpuid_sgx( fn update_cpuid_sgx(
cpuid: &mut Vec<CpuIdEntry>, cpuid: &mut Vec<CpuIdEntry>,
epc_sections: &[SgxEpcSection], epc_sections: Vec<SgxEpcSection>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Something's wrong if there's no EPC section. // Something's wrong if there's no EPC section.
if epc_sections.is_empty() { if epc_sections.is_empty() {
@@ -1436,7 +1294,6 @@ mod tests {
None, None,
None, None,
None, None,
None,
); );
assert!(config_err.is_err()); assert!(config_err.is_err());
@@ -1459,7 +1316,6 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
@@ -1487,7 +1343,6 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
@@ -1501,7 +1356,6 @@ mod tests {
None, None,
None, None,
None, None,
None,
) )
.unwrap(); .unwrap();
} }
@@ -1530,25 +1384,4 @@ mod tests {
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}")); assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
} }
#[test]
fn test_get_x2apic_id() {
let x2apic_id = get_x2apic_id(0, Some((2, 3, 1)));
assert_eq!(x2apic_id, 0);
let x2apic_id = get_x2apic_id(1, Some((2, 3, 1)));
assert_eq!(x2apic_id, 1);
let x2apic_id = get_x2apic_id(2, Some((2, 3, 1)));
assert_eq!(x2apic_id, 2);
let x2apic_id = get_x2apic_id(6, Some((2, 3, 1)));
assert_eq!(x2apic_id, 8);
let x2apic_id = get_x2apic_id(7, Some((2, 3, 1)));
assert_eq!(x2apic_id, 9);
let x2apic_id = get_x2apic_id(8, Some((2, 3, 1)));
assert_eq!(x2apic_id, 10);
}
} }

View File

@@ -6,9 +6,10 @@
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START}; use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
use crate::x86_64::{get_x2apic_id, mpspec}; use crate::x86_64::mpspec;
use crate::GuestMemoryMmap; use crate::GuestMemoryMmap;
use libc::c_char; use libc::c_char;
use std::io;
use std::mem; use std::mem;
use std::result; use std::result;
use std::slice; use std::slice;
@@ -125,18 +126,9 @@ fn compute_mp_size(num_cpus: u8) -> usize {
} }
/// Performs setup of the MP table for the given `num_cpus`. /// Performs setup of the MP table for the given `num_cpus`.
pub fn setup_mptable( pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8) -> Result<()> {
offset: GuestAddress, if num_cpus as u32 > MAX_SUPPORTED_CPUS {
mem: &GuestMemoryMmap, return Err(Error::TooManyCpus);
num_cpus: u8,
topology: Option<(u8, u8, u8)>,
) -> Result<()> {
if num_cpus > 0 {
let cpu_id_max = num_cpus - 1;
let x2apic_id_max = get_x2apic_id(cpu_id_max.into(), topology);
if x2apic_id_max >= MAX_SUPPORTED_CPUS {
return Err(Error::TooManyCpus);
}
} }
// Used to keep track of the next base pointer into the MP table. // Used to keep track of the next base pointer into the MP table.
@@ -150,7 +142,7 @@ pub fn setup_mptable(
} }
let mut checksum: u8 = 0; let mut checksum: u8 = 0;
let ioapicid: u8 = MAX_SUPPORTED_CPUS as u8 + 1; let ioapicid: u8 = num_cpus + 1;
// The checked_add here ensures the all of the following base_mp.unchecked_add's will be without // The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
// overflow. // overflow.
@@ -162,7 +154,7 @@ pub fn setup_mptable(
return Err(Error::AddressOverflow); return Err(Error::AddressOverflow);
} }
mem.read_exact_volatile_from(base_mp, &mut vec![0; mp_size].as_slice(), mp_size) mem.read_exact_from(base_mp, &mut io::repeat(0), mp_size)
.map_err(Error::Clear)?; .map_err(Error::Clear)?;
{ {
@@ -188,7 +180,7 @@ pub fn setup_mptable(
for cpu_id in 0..num_cpus { for cpu_id in 0..num_cpus {
let mut mpc_cpu = MpcCpuWrapper(mpspec::mpc_cpu::default()); let mut mpc_cpu = MpcCpuWrapper(mpspec::mpc_cpu::default());
mpc_cpu.0.type_ = mpspec::MP_PROCESSOR as u8; mpc_cpu.0.type_ = mpspec::MP_PROCESSOR as u8;
mpc_cpu.0.apicid = get_x2apic_id(cpu_id as u32, topology) as u8; mpc_cpu.0.apicid = cpu_id;
mpc_cpu.0.apicver = APIC_VERSION; mpc_cpu.0.apicver = APIC_VERSION;
mpc_cpu.0.cpuflag = mpspec::CPU_ENABLED as u8 mpc_cpu.0.cpuflag = mpspec::CPU_ENABLED as u8
| if cpu_id == 0 { | if cpu_id == 0 {
@@ -299,10 +291,7 @@ pub fn setup_mptable(
mod tests { mod tests {
use super::*; use super::*;
use crate::layout::MPTABLE_START; use crate::layout::MPTABLE_START;
use vm_memory::{ use vm_memory::{GuestAddress, GuestUsize};
bitmap::BitmapSlice, GuestAddress, GuestUsize, VolatileMemoryError, VolatileSlice,
WriteVolatile,
};
fn table_entry_size(type_: u8) -> usize { fn table_entry_size(type_: u8) -> usize {
match type_ as u32 { match type_ as u32 {
@@ -321,7 +310,7 @@ mod tests {
let mem = let mem =
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap(); GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap(); setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
} }
#[test] #[test]
@@ -330,7 +319,7 @@ mod tests {
let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus) - 1)]) let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus) - 1)])
.unwrap(); .unwrap();
assert!(setup_mptable(MPTABLE_START, &mem, num_cpus, None).is_err()); assert!(setup_mptable(MPTABLE_START, &mem, num_cpus).is_err());
} }
#[test] #[test]
@@ -339,7 +328,7 @@ mod tests {
let mem = let mem =
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap(); GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap(); setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap(); let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
@@ -355,31 +344,27 @@ mod tests {
let mem = let mem =
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap(); GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap(); setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap(); let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize); let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
let mpc_table: MpcTableWrapper = mem.read_obj(mpc_offset).unwrap(); let mpc_table: MpcTableWrapper = mem.read_obj(mpc_offset).unwrap();
struct Sum(u8); struct Sum(u8);
impl WriteVolatile for Sum { impl io::Write for Sum {
fn write_volatile<B: BitmapSlice>( fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
&mut self, for v in buf.iter() {
buf: &VolatileSlice<B>,
) -> result::Result<usize, VolatileMemoryError> {
let mut tmp = vec![0u8; buf.len()];
tmp.write_all_volatile(buf)?;
for v in tmp.iter() {
self.0 = self.0.wrapping_add(*v); self.0 = self.0.wrapping_add(*v);
} }
Ok(buf.len()) Ok(buf.len())
} }
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
} }
let mut sum = Sum(0); let mut sum = Sum(0);
mem.write_volatile_to(mpc_offset, &mut sum, mpc_table.0.length as usize) mem.write_to(mpc_offset, &mut sum, mpc_table.0.length as usize)
.unwrap(); .unwrap();
assert_eq!(sum.0, 0); assert_eq!(sum.0, 0);
} }
@@ -393,7 +378,7 @@ mod tests {
.unwrap(); .unwrap();
for i in 0..MAX_SUPPORTED_CPUS as u8 { for i in 0..MAX_SUPPORTED_CPUS as u8 {
setup_mptable(MPTABLE_START, &mem, i, None).unwrap(); setup_mptable(MPTABLE_START, &mem, i).unwrap();
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap(); let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize); let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
@@ -426,7 +411,7 @@ mod tests {
let mem = let mem =
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus as u8))]).unwrap(); GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus as u8))]).unwrap();
let result = setup_mptable(MPTABLE_START, &mem, cpus as u8, None); let result = setup_mptable(MPTABLE_START, &mem, cpus as u8);
assert!(result.is_err()); assert!(result.is_err());
} }
} }

View File

@@ -10,18 +10,18 @@ io_uring = ["dep:io-uring"]
[dependencies] [dependencies]
byteorder = "1.4.3" byteorder = "1.4.3"
crc-any = "2.4.4" crc32c = "0.6.4"
io-uring = { version = "0.6.2", optional = true } io-uring = { version = "0.6.1", optional = true }
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
remain = "0.2.11" remain = "0.2.11"
smallvec = "1.11.0" smallvec = "1.11.0"
thiserror = "1.0.40" thiserror = "1.0.40"
uuid = { version = "1.3.4", features = ["v4"] } uuid = { version = "1.3.4", features = ["v4"] }
versionize = "0.2.0" versionize = "0.1.10"
versionize_derive = "0.1.6" versionize_derive = "0.1.4"
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] } virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.11.0" virtio-queue = "0.9.0"
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"

View File

@@ -24,7 +24,6 @@ pub mod qcow_sync;
/// ///
/// Enabled with the `"io_uring"` feature /// Enabled with the `"io_uring"` feature
pub mod raw_async; pub mod raw_async;
pub mod raw_async_aio;
pub mod raw_sync; pub mod raw_sync;
pub mod vhd; pub mod vhd;
pub mod vhdx; pub mod vhdx;
@@ -62,7 +61,6 @@ use vm_memory::{
GuestMemoryError, GuestMemoryLoadGuard, GuestMemoryError, GuestMemoryLoadGuard,
}; };
use vm_virtio::{AccessPlatform, Translatable}; use vm_virtio::{AccessPlatform, Translatable};
use vmm_sys_util::aio;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::{ioctl_io_nr, ioctl_ioc_nr}; use vmm_sys_util::{ioctl_io_nr, ioctl_ioc_nr};
@@ -143,14 +141,10 @@ pub enum ExecuteError {
Flush(io::Error), Flush(io::Error),
#[error("Failed to read: {0}")] #[error("Failed to read: {0}")]
Read(GuestMemoryError), Read(GuestMemoryError),
#[error("Failed to read_exact: {0}")]
ReadExact(io::Error),
#[error("Failed to seek: {0}")] #[error("Failed to seek: {0}")]
Seek(io::Error), Seek(io::Error),
#[error("Failed to write: {0}")] #[error("Failed to write: {0}")]
Write(GuestMemoryError), Write(GuestMemoryError),
#[error("Failed to write_all: {0}")]
WriteAll(io::Error),
#[error("Unsupported request: {0}")] #[error("Unsupported request: {0}")]
Unsupported(u32), Unsupported(u32),
#[error("Failed to submit io uring: {0}")] #[error("Failed to submit io uring: {0}")]
@@ -173,10 +167,8 @@ impl ExecuteError {
ExecuteError::BadRequest(_) => VIRTIO_BLK_S_IOERR, ExecuteError::BadRequest(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR, ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::Read(_) => VIRTIO_BLK_S_IOERR, ExecuteError::Read(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::ReadExact(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::Seek(_) => VIRTIO_BLK_S_IOERR, ExecuteError::Seek(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::Write(_) => VIRTIO_BLK_S_IOERR, ExecuteError::Write(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::WriteAll(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP, ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP,
ExecuteError::SubmitIoUring(_) => VIRTIO_BLK_S_IOERR, ExecuteError::SubmitIoUring(_) => VIRTIO_BLK_S_IOERR,
ExecuteError::GetHostAddress(_) => VIRTIO_BLK_S_IOERR, ExecuteError::GetHostAddress(_) => VIRTIO_BLK_S_IOERR,
@@ -357,21 +349,13 @@ impl Request {
match self.request_type { match self.request_type {
RequestType::In => { RequestType::In => {
let mut buf = vec![0u8; *data_len as usize]; mem.read_exact_from(*data_addr, disk, *data_len as usize)
disk.read_exact(&mut buf).map_err(ExecuteError::ReadExact)?; .map_err(ExecuteError::Read)?;
mem.read_exact_volatile_from(
*data_addr,
&mut buf.as_slice(),
*data_len as usize,
)
.map_err(ExecuteError::Read)?;
len += data_len; len += data_len;
} }
RequestType::Out => { RequestType::Out => {
let mut buf: Vec<u8> = Vec::new(); mem.write_all_to(*data_addr, disk, *data_len as usize)
mem.write_all_volatile_to(*data_addr, &mut buf, *data_len as usize)
.map_err(ExecuteError::Write)?; .map_err(ExecuteError::Write)?;
disk.write_all(&buf).map_err(ExecuteError::WriteAll)?;
if !self.writeback { if !self.writeback {
disk.flush().map_err(ExecuteError::Flush)?; disk.flush().map_err(ExecuteError::Flush)?;
} }
@@ -581,11 +565,6 @@ unsafe impl ByteValued for VirtioBlockConfig {}
// SAFETY: data structure only contain a series of integers // SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for VirtioBlockGeometry {} unsafe impl ByteValued for VirtioBlockGeometry {}
/// Check if aio can be used on the current system.
pub fn block_aio_is_supported() -> bool {
aio::IoContext::new(1).is_ok()
}
/// Check if io_uring for block device can be used on the current system, as /// Check if io_uring for block device can be used on the current system, as
/// it correctly supports the expected io_uring features. /// it correctly supports the expected io_uring features.
pub fn block_io_uring_is_supported() -> bool { pub fn block_io_uring_is_supported() -> bool {

View File

@@ -136,7 +136,7 @@ impl<T: Cacheable> CacheMap<T> {
mod tests { mod tests {
use super::*; use super::*;
struct NumCache(()); struct NumCache(pub u64);
impl Cacheable for NumCache { impl Cacheable for NumCache {
fn dirty(&self) -> bool { fn dirty(&self) -> bool {
true true
@@ -148,28 +148,28 @@ mod tests {
let mut cache = CacheMap::<NumCache>::new(3); let mut cache = CacheMap::<NumCache>::new(3);
let mut evicted = None; let mut evicted = None;
cache cache
.insert(0, NumCache(()), |index, _| { .insert(0, NumCache(5), |index, _| {
evicted = Some(index); evicted = Some(index);
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(evicted, None); assert_eq!(evicted, None);
cache cache
.insert(1, NumCache(()), |index, _| { .insert(1, NumCache(6), |index, _| {
evicted = Some(index); evicted = Some(index);
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(evicted, None); assert_eq!(evicted, None);
cache cache
.insert(2, NumCache(()), |index, _| { .insert(2, NumCache(7), |index, _| {
evicted = Some(index); evicted = Some(index);
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(evicted, None); assert_eq!(evicted, None);
cache cache
.insert(3, NumCache(()), |index, _| { .insert(3, NumCache(8), |index, _| {
evicted = Some(index); evicted = Some(index);
Ok(()) Ok(())
}) })

View File

@@ -1,150 +0,0 @@
// Copyright © 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
//
// Copyright © 2023 Crusoe Energy Systems LLC
//
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
};
use crate::DiskTopology;
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::aio;
use vmm_sys_util::eventfd::EventFd;
pub struct RawFileDiskAio {
file: File,
}
impl RawFileDiskAio {
pub fn new(file: File) -> Self {
RawFileDiskAio { file }
}
}
impl DiskFile for RawFileDiskAio {
fn size(&mut self) -> DiskFileResult<u64> {
self.file
.seek(SeekFrom::End(0))
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)
.map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>)
}
fn topology(&mut self) -> DiskTopology {
if let Ok(topology) = DiskTopology::probe(&self.file) {
topology
} else {
warn!("Unable to get device topology. Using default topology");
DiskTopology::default()
}
}
}
pub struct RawFileAsyncAio {
fd: RawFd,
ctx: aio::IoContext,
eventfd: EventFd,
}
impl RawFileAsyncAio {
pub fn new(fd: RawFd, queue_depth: u32) -> std::io::Result<Self> {
let eventfd = EventFd::new(libc::EFD_NONBLOCK)?;
let ctx = aio::IoContext::new(queue_depth)?;
Ok(RawFileAsyncAio { fd, ctx, eventfd })
}
}
impl AsyncIo for RawFileAsyncAio {
fn notifier(&self) -> &EventFd {
&self.eventfd
}
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
let iocbs = [&mut aio::IoControlBlock {
aio_fildes: self.fd.as_raw_fd() as u32,
aio_lio_opcode: aio::IOCB_CMD_PREADV as u16,
aio_buf: iovecs.as_ptr() as u64,
aio_nbytes: iovecs.len() as u64,
aio_offset: offset,
aio_data: user_data,
aio_flags: aio::IOCB_FLAG_RESFD,
aio_resfd: self.eventfd.as_raw_fd() as u32,
..Default::default()
}];
let _ = self
.ctx
.submit(&iocbs[..])
.map_err(AsyncIoError::ReadVectored)?;
Ok(())
}
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
let iocbs = [&mut aio::IoControlBlock {
aio_fildes: self.fd.as_raw_fd() as u32,
aio_lio_opcode: aio::IOCB_CMD_PWRITEV as u16,
aio_buf: iovecs.as_ptr() as u64,
aio_nbytes: iovecs.len() as u64,
aio_offset: offset,
aio_data: user_data,
aio_flags: aio::IOCB_FLAG_RESFD,
aio_resfd: self.eventfd.as_raw_fd() as u32,
..Default::default()
}];
let _ = self
.ctx
.submit(&iocbs[..])
.map_err(AsyncIoError::WriteVectored)?;
Ok(())
}
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
if let Some(user_data) = user_data {
let iocbs = [&mut aio::IoControlBlock {
aio_fildes: self.fd.as_raw_fd() as u32,
aio_lio_opcode: aio::IOCB_CMD_FSYNC as u16,
aio_data: user_data,
aio_flags: aio::IOCB_FLAG_RESFD,
aio_resfd: self.eventfd.as_raw_fd() as u32,
..Default::default()
}];
let _ = self.ctx.submit(&iocbs[..]).map_err(AsyncIoError::Fsync)?;
} else {
// SAFETY: FFI call with a valid fd
unsafe { libc::fsync(self.fd) };
}
Ok(())
}
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
let mut events: [aio::IoEvent; 1] = [aio::IoEvent::default()];
let rc = self.ctx.get_events(0, &mut events, None).unwrap();
if rc == 0 {
None
} else {
Some((events[0].data, events[0].res as i32))
}
}
}

View File

@@ -192,9 +192,7 @@ impl Header {
}; };
new_header.get_header_as_buffer(&mut buffer); new_header.get_header_as_buffer(&mut buffer);
let mut crc = crc_any::CRC::crc32c(); new_header.checksum = crc32c::crc32c(&buffer);
crc.digest(&buffer);
new_header.checksum = crc.get_crc() as u32;
new_header.get_header_as_buffer(&mut buffer); new_header.get_header_as_buffer(&mut buffer);
f.seek(SeekFrom::Start(start)) f.seek(SeekFrom::Start(start))
@@ -482,10 +480,7 @@ pub fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> Result<u32>
// Zero the checksum in the buffer // Zero the checksum in the buffer
LittleEndian::write_u32(csum_buf, 0); LittleEndian::write_u32(csum_buf, 0);
// Calculate the checksum on the resulting buffer // Calculate the checksum on the resulting buffer
let mut crc = crc_any::CRC::crc32c(); let new_csum = crc32c::crc32c(buffer);
crc.digest(&buffer);
let new_csum = crc.get_crc() as u32;
// Put back the original checksum in the buffer // Put back the original checksum in the buffer
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum); LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum);

View File

@@ -8,22 +8,22 @@ edition = "2021"
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" } acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.75" anyhow = "1.0.75"
arch = { path = "../arch" } arch = { path = "../arch" }
bitflags = "2.4.1" bitflags = "2.3.3"
byteorder = "1.4.3" byteorder = "1.4.3"
event_monitor = { path = "../event_monitor" } event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
pci = { path = "../pci" } pci = { path = "../pci" }
thiserror = "1.0.40" thiserror = "1.0.40"
tpm = { path = "../tpm" } tpm = { path = "../tpm" }
versionize = "0.2.0" versionize = "0.1.10"
versionize_derive = "0.1.6" versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = "0.14.0" vm-memory = "0.12.2"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"
[target.'cfg(target_arch = "aarch64")'.dependencies] [target.'cfg(target_arch = "aarch64")'.dependencies]
arch = { path = "../arch" } arch = { path = "../arch" }

View File

@@ -166,8 +166,8 @@ impl Serial {
Self::new(id, interrupt, None, state) Self::new(id, interrupt, None, state)
} }
pub fn set_out(&mut self, out: Option<Box<dyn io::Write + Send>>) { pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
self.out = out; self.out = Some(out);
} }
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would /// Queues raw bytes for the guest to read and signals the interrupt if the line status would

View File

@@ -201,8 +201,8 @@ impl Pl011 {
} }
} }
pub fn set_out(&mut self, out: Option<Box<dyn io::Write + Send>>) { pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
self.out = out; self.out = Some(out);
} }
fn state(&self) -> Pl011State { fn state(&self) -> Pl011State {

View File

@@ -181,9 +181,8 @@ impl PciDevice for PvPanicDevice {
fn allocate_bars( fn allocate_bars(
&mut self, &mut self,
_allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
mmio32_allocator: &mut AddressAllocator, _mmio_allocator: &mut AddressAllocator,
_mmio64_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>, resources: Option<Vec<Resource>>,
) -> std::result::Result<Vec<PciBarConfiguration>, PciDeviceError> { ) -> std::result::Result<Vec<PciBarConfiguration>, PciDeviceError> {
let mut bars = Vec::new(); let mut bars = Vec::new();
@@ -191,8 +190,10 @@ impl PciDevice for PvPanicDevice {
let bar_id = 0; let bar_id = 0;
let region_size = PVPANIC_DEVICE_MMIO_SIZE; let region_size = PVPANIC_DEVICE_MMIO_SIZE;
let restoring = resources.is_some(); let restoring = resources.is_some();
let bar_addr = mmio32_allocator let bar_addr = allocator
.allocate(None, region_size, Some(PVPANIC_DEVICE_MMIO_ALIGNMENT)) .lock()
.unwrap()
.allocate_mmio_hole_addresses(None, region_size, Some(PVPANIC_DEVICE_MMIO_ALIGNMENT))
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?; .ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
let bar = PciBarConfiguration::default() let bar = PciBarConfiguration::default()
@@ -217,12 +218,11 @@ impl PciDevice for PvPanicDevice {
fn free_bars( fn free_bars(
&mut self, &mut self,
_allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
mmio32_allocator: &mut AddressAllocator, _mmio_allocator: &mut AddressAllocator,
_mmio64_allocator: &mut AddressAllocator,
) -> std::result::Result<(), PciDeviceError> { ) -> std::result::Result<(), PciDeviceError> {
for bar in self.bar_regions.drain(..) { for bar in self.bar_regions.drain(..) {
mmio32_allocator.free(GuestAddress(bar.addr()), bar.size()); allocator.free_mmio_hole_addresses(GuestAddress(bar.addr()), bar.size());
} }
Ok(()) Ok(())

View File

@@ -36,5 +36,3 @@ You can run a SEV-SNP VM using the following command:
--memory size=1G \ --memory size=1G \
--disk path=ubuntu.img --disk path=ubuntu.img
``` ```
For more information related to Microsoft Hypervisor please see [mshv.md](mshv.md)

View File

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

View File

@@ -54,7 +54,7 @@ Value is a boolean set to `off` by default.
_Example_ _Example_
``` ```
--balloon size=2G,deflate_on_oom=on --ballloon size=2G,deflate_on_oom=on
``` ```
### `free_page_reporting` ### `free_page_reporting`
@@ -72,5 +72,5 @@ Value is a boolean set to `off` by default.
_Example_ _Example_
``` ```
--balloon size=0,free_page_reporting=on --ballloon size=0,free_page_reporting=on
``` ```

View File

@@ -1,81 +0,0 @@
# Code coverage
LLVM provides a set of tools to collect code coverage data and present the data
in human-consumable forms.
## Building a suitable binary
The compiler flag to generate code coverage data has been stabilized since Rust
1.60.
An instrumented binary can be built with the following command:
```shell
cargo clean && RUSTFLAGS='-C instrument-coverage' cargo build
```
Using either `debug` or `release` profile is fine. You will need to adjust
the path for some commands.
## Running the binary
Run the binary as you normally would. When the process exits, you will see
files with the prefix `profraw`.
Multiple runs of the same binary will produce multiple `profraw` files.
The more diverse the runs are, the better. Try to exercise different features
as much as possible.
## Combining raw data
Raw data files can be combined with `llvm-profdata`.
```shell
rustup component add llvm-tools-preview
# Assuming profraw files reside in the current directory and its children directories
find . -name '*.profraw' -exec llvm-profdata merge -sparse {} -o coverage.profdata \;
```
A file named `coverage.profdata` will be generated.
## Generating HTML files for human consumption
This can be done either with LLVM or `grcov`.
Here is an example using grcov.
```shell
cargo install grcov
# Assuming the profdata file is in the top level directory of the Cloud Hypervisor repository
grcov . --binary-path ./target/x86_64-unknown-linux-gnu/release -s . -t html --branch --ignore-not-existing -o coverage-html-output/
```
You can then open the `index.html` file under coverage-html-output to see the
results.
## Notes on running the in-tree integration tests and unit tests
Please set RUSTFLAGS the same way while invoking `dev_cli.sh`. The script will
pass RUSTFLAGS to the container.
Since the `profraw` files are generated from within the container, the file
paths embedded in the data files are going to be different. It is easier to do
the data processing from within the container if you don't want to fight the
tool chain.
```shell
# Get a shell
./scripts/dev_cli.sh shell
# Install llvm-tools-preview for llvm-profdata
rustup component add llvm-tools-preview
# Merge data files by using the following command
find . -name '*.profraw' -exec `rustc --print sysroot`/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse {} -o coverage.profdata \;
# As of writing, the container has Rust 1.67.1. It is too old for grcov.
rustup install stable
cargo +stable install grcov
# Run grcov as usual
grcov . --binary-path ./target/x86_64-unknown-linux-gnu/release -s . -t html --branch --ignore-not-existing -o coverage-html-output/
```

View File

@@ -170,7 +170,7 @@ We usually start from one of the custom cloud image we have previously created
but we can use a stock cloud image as well. but we can use a stock cloud image as well.
```bash ```bash
wget https://ch-images.azureedge.net/jammy-server-cloudimg-amd64-custom-20230119-0.raw wget https://cloud-hypervisor.azureedge.net/jammy-server-cloudimg-amd64-custom-20230119-0.raw
mv jammy-server-cloudimg-amd64-custom-20230119-0.raw jammy-server-cloudimg-amd64-nvidia.raw mv jammy-server-cloudimg-amd64-custom-20230119-0.raw jammy-server-cloudimg-amd64-nvidia.raw
``` ```
@@ -326,4 +326,4 @@ VM will be booted with this image.
``` ```
sudo cloud-init clean sudo cloud-init clean
``` ```

View File

@@ -36,7 +36,7 @@ Assuming parts of the guest software stack have been instrumented to use the
`cloud-hypervisor` debug I/O port, we may want to gather the related logs. `cloud-hypervisor` debug I/O port, we may want to gather the related logs.
To do so we need to start `cloud-hypervisor` with the right debug level To do so we need to start `cloud-hypervisor` with the right debug level
(`-vvv`). It is also recommended to have it log into a dedicated file in order (`-v -v -v`). It is also recommended to have it log into a dedicated file in order
to easily grep for the tracing logs (e.g. to easily grep for the tracing logs (e.g.
`--log-file /tmp/cloud-hypervisor.log`): `--log-file /tmp/cloud-hypervisor.log`):
@@ -48,7 +48,7 @@ to easily grep for the tracing logs (e.g.
--memory size=1024M \ --memory size=1024M \
--rng \ --rng \
--log-file /tmp/ch-fw.log \ --log-file /tmp/ch-fw.log \
-vvv -v -v -v
``` ```
After booting the guest, we then have to grep for the debug I/O port traces in After booting the guest, we then have to grep for the debug I/O port traces in

View File

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

View File

@@ -27,16 +27,16 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--memory size=1024M \ --memory size=1024M \
--net "tap=,mac=,ip=,mask=" \ --net "tap=,mac=,ip=,mask=" \
--rng \ --rng \
--api-socket=/tmp/ch-socket --api-socket /tmp/ch-socket
$ popd $ popd
``` ```
Notice the addition of `--api-socket=/tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`. Notice the addition of `--api-socket /tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
To ask the VMM to add additional vCPUs then use the resize API: To ask the VMM to add additional vCPUs then use the resize API:
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 8 ./ch-remote --api-socket /tmp/ch-socket resize --cpus 8
``` ```
The extra vCPU threads will be created and advertised to the running kernel. The kernel does not bring up the CPUs immediately and instead the user must "online" them from inside the VM: The extra vCPU threads will be created and advertised to the running kernel. The kernel does not bring up the CPUs immediately and instead the user must "online" them from inside the VM:
@@ -56,7 +56,7 @@ After a reboot the added CPUs will remain.
Removing CPUs works similarly by reducing the number in the "desired_vcpus" field of the reisze API. The CPUs will be automatically offlined inside the guest so there is no need to run any commands inside the guest: Removing CPUs works similarly by reducing the number in the "desired_vcpus" field of the reisze API. The CPUs will be automatically offlined inside the guest so there is no need to run any commands inside the guest:
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 2 ./ch-remote --api-socket /tmp/ch-socket resize --cpus 2
``` ```
As per adding CPUs to the guest, after a reboot the VM will be running with the reduced number of vCPUs. As per adding CPUs to the guest, after a reboot the VM will be running with the reduced number of vCPUs.
@@ -85,7 +85,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--memory size=1024M,hotplug_size=8192M \ --memory size=1024M,hotplug_size=8192M \
--net "tap=,mac=,ip=,mask=" \ --net "tap=,mac=,ip=,mask=" \
--rng \ --rng \
--api-socket=/tmp/ch-socket --api-socket /tmp/ch-socket
$ popd $ popd
``` ```
@@ -98,7 +98,7 @@ root@ch-guest ~ # echo online | sudo tee /sys/devices/system/memory/auto_online_
To ask the VMM to expand the RAM for the VM: To ask the VMM to expand the RAM for the VM:
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G ./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
``` ```
The new memory is now available to use inside the VM: The new memory is now available to use inside the VM:
@@ -134,14 +134,14 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--disk path=focal-server-cloudimg-amd64.raw \ --disk path=focal-server-cloudimg-amd64.raw \
--memory size=1024M,hotplug_size=8192M,hotplug_method=virtio-mem \ --memory size=1024M,hotplug_size=8192M,hotplug_method=virtio-mem \
--net "tap=,mac=,ip=,mask=" \ --net "tap=,mac=,ip=,mask=" \
--api-socket=/tmp/ch-socket --api-socket /tmp/ch-socket
$ popd $ popd
``` ```
To ask the VMM to expand the RAM for the VM (request is in bytes): To ask the VMM to expand the RAM for the VM (request is in bytes):
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G ./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
``` ```
The new memory is now available to use inside the VM: The new memory is now available to use inside the VM:
@@ -172,17 +172,17 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
--cpus boot=4 \ --cpus boot=4 \
--memory size=1024M \ --memory size=1024M \
--net "tap=,mac=,ip=,mask=" \ --net "tap=,mac=,ip=,mask=" \
--api-socket=/tmp/ch-socket --api-socket /tmp/ch-socket
``` ```
Notice the addition of `--api-socket=/tmp/ch-socket`. Notice the addition of `--api-socket /tmp/ch-socket`.
### Add VFIO Device ### Add VFIO Device
To ask the VMM to add additional VFIO device then use the `add-device` API. To ask the VMM to add additional VFIO device then use the `add-device` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/ ./ch-remote --api-socket /tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/
``` ```
### Add Disk Device ### Add Disk Device
@@ -190,7 +190,7 @@ To ask the VMM to add additional VFIO device then use the `add-device` API.
To ask the VMM to add additional disk device then use the `add-disk` API. To ask the VMM to add additional disk device then use the `add-disk` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-disk path=/foo/bar/cloud.img ./ch-remote --api-socket /tmp/ch-socket add-disk path=/foo/bar/cloud.img
``` ```
### Add Fs Device ### Add Fs Device
@@ -198,7 +198,7 @@ To ask the VMM to add additional disk device then use the `add-disk` API.
To ask the VMM to add additional fs device then use the `add-fs` API. To ask the VMM to add additional fs device then use the `add-fs` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock ./ch-remote --api-socket /tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock
``` ```
### Add Net Device ### Add Net Device
@@ -206,7 +206,7 @@ To ask the VMM to add additional fs device then use the `add-fs` API.
To ask the VMM to add additional network device then use the `add-net` API. To ask the VMM to add additional network device then use the `add-net` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-net tap=chtap0 ./ch-remote --api-socket /tmp/ch-socket add-net tap=chtap0
``` ```
### Add Pmem Device ### Add Pmem Device
@@ -214,7 +214,7 @@ To ask the VMM to add additional network device then use the `add-net` API.
To ask the VMM to add additional PMEM device then use the `add-pmem` API. To ask the VMM to add additional PMEM device then use the `add-pmem` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-pmem file=/foo/bar.cloud.img ./ch-remote --api-socket /tmp/ch-socket add-pmem file=/foo/bar.cloud.img
``` ```
### Add Vsock Device ### Add Vsock Device
@@ -222,7 +222,7 @@ To ask the VMM to add additional PMEM device then use the `add-pmem` API.
To ask the VMM to add additional vsock device then use the `add-vsock` API. To ask the VMM to add additional vsock device then use the `add-vsock` API.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock ./ch-remote --api-socket /tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock
``` ```
### Common Across All PCI Devices ### Common Across All PCI Devices
@@ -244,7 +244,7 @@ After a reboot the added PCI device will remain.
Removing a PCI device works the same way for all kind of PCI devices. The unique identifier related to the device must be provided. This identifier can be provided by the user when adding the new device, or by default Cloud Hypervisor will assign one. Removing a PCI device works the same way for all kind of PCI devices. The unique identifier related to the device must be provided. This identifier can be provided by the user when adding the new device, or by default Cloud Hypervisor will assign one.
```shell ```shell
./ch-remote --api-socket=/tmp/ch-socket remove-device _disk0 ./ch-remote --api-socket /tmp/ch-socket remove-device _disk0
``` ```
As per adding a PCI device to the guest, after a reboot the VM will be running without the removed PCI device. As per adding a PCI device to the guest, after a reboot the VM will be running without the removed PCI device.

View File

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

View File

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

View File

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

View File

@@ -516,7 +516,7 @@ different distances, it can be described with the following example.
_Example_ _Example_
``` ```
--numa guest_numa_id=0,distances=[1@15,2@25] guest_numa_id=1,distances=[0@15,2@20] guest_numa_id=2,distances=[0@25,1@20] --numa guest_numa_id=0,distances=[1@15,2@25] --numa guest_numa_id=1,distances=[0@15,2@20] guest_numa_id=2,distances=[0@25,1@20]
``` ```
### `memory_zones` ### `memory_zones`
@@ -540,14 +540,14 @@ demarcate the list.
Note that a memory zone must belong to a single NUMA node. The following Note that a memory zone must belong to a single NUMA node. The following
configuration is incorrect, therefore not allowed: configuration is incorrect, therefore not allowed:
`--numa guest_numa_id=0,memory_zones=mem0 guest_numa_id=1,memory_zones=mem0` `--numa guest_numa_id=0,memory_zones=mem0 --numa guest_numa_id=1,memory_zones=mem0`
_Example_ _Example_
``` ```
--memory size=0 --memory size=0
--memory-zone id=mem0,size=1G id=mem1,size=1G id=mem2,size=1G --memory-zone id=mem0,size=1G id=mem1,size=1G --memory-zone id=mem2,size=1G
--numa guest_numa_id=0,memory_zones=[mem0,mem2] guest_numa_id=1,memory_zones=mem1 --numa guest_numa_id=0,memory_zones=[mem0,mem2] --numa guest_numa_id=1,memory_zones=mem1
``` ```
### `sgx_epc_sections` ### `sgx_epc_sections`
@@ -567,21 +567,12 @@ _Example_
``` ```
--sgx-epc id=epc0,size=32M id=epc1,size=64M id=epc2,size=32M --sgx-epc id=epc0,size=32M id=epc1,size=64M id=epc2,size=32M
--numa guest_numa_id=0,sgx_epc_sections=epc1 guest_numa_id=1,sgx_epc_sections=[epc0,epc2] --numa guest_numa_id=0,sgx_epc_sections=epc1 --numa guest_numa_id=1,sgx_epc_sections=[epc0,epc2]
``` ```
### PCI bus ### PCI bus
Cloud Hypervisor supports guests with one or more PCI segments. The default PCI segment always Cloud Hypervisor supports only one PCI bus, which is why it has been tied to
has affinity to NUMA node 0. Be default, all other PCI segments have afffinity to NUMA node 0. the NUMA node 0 by default. It is the user responsibility to organize the NUMA
The user may configure the NUMA affinity for any additional PCI segments. nodes correctly so that vCPUs and guest RAM which should be located on the same
NUMA node as the PCI bus end up on the NUMA node 0.
_Example_
```
--platform num_pci_segments=2
--memory-zone size=16G,host_numa_node=0,id=mem0
--memory-zone size=16G,host_numa_node=1,id=mem1
--numa guest_numa_id=0,memory_zones=mem0,pci_segments=[0]
--numa guest_numa_id=1,memory_zones=mem1,pci_segments=[1]
```

View File

@@ -1,48 +0,0 @@
# Microsoft Hypervisor
The Microsoft Hypervisor is a Type 1 hypervisor which runs on x64 and ARM64 architectures. As the foundation of the Hyper-V virtualization stack, it runs millions of Linux and Windows guests in Azure and on-premises deployments. It supports nested virtualization, and security features like AMD's SEV-SNP. It also supports various features in Windows such as [Device guard and confidential guard](https://techcommunity.microsoft.com/t5/iis-support-blog/windows-10-device-guard-and-credential-guard-demystified/ba-p/376419), and [WSL2](https://docs.microsoft.com/en-us/windows/wsl/wsl2-faq)
Since 2020, Microsoft has been releasing open-source components to support Linux running as root partition on the Microsoft Hypervisor.
1. Kernel patches to support Linux booting as root partition
2. A Linux kernel driver exposing an IOCTL interface for managing guest partitions, via a device node - /dev/mshv
3. Rust bindings and IOCTL wrappers
4. IGVM related crates
## Components
The following components are related to MSHV support with Cloud-Hypervisor:
* [igvm-crates](https://github.com/microsoft/igvm) : Parsing IGVM file
* [mshv-crates](https://github.com/rust-vmm/mshv) : Rust crates to interact with kernel module (/dev/mshv)
* [igvm-tooling](https://github.com/microsoft/igvm-tooling) : Tool to generate IGVM file
## IGVM
Independent Guest Virtual Machine (IGVM) file format.The format specification can be found in the igvm_defs crate, with a Rust implementation of the binary format in the igvm crate.
The IGVM file format is designed to encapsulate all information required to launch a virtual machine on any given virtualization stack, with support for different isolation technologies such as AMD SEV-SNP and Intel TDX.
At a conceptual level, this file format is a set of commands created by the tool that generated the file, used by the loader to construct the initial guest state. The file format also contains measurement information that the underlying platform will use to confirm that the file was loaded correctly and signed by the appropriate authorities.
Cloud Hypervisor can be built using igvm feature flag along with mshv and/or sev-snp. IGVM only works with MSHV.
## SEV-SNP
AMD's [Secure Encrypted Virtualization (SEV)](https://www.amd.com/en/developer/sev.html) and extensions such as Secure Nested Paging (SEV-SNP) encrypt memory and restrict access to a guest VM's memory and registers, securing it against a compromised hypervisor or VMM. They utilize the Platform Security Processor (PSP) to store keys and encrypt/decrypt the data. Microsoft has been continuously adding/improving support for SEV-SNP on Microsoft Hyper-V. Cloud-Hypervisor can be built with the sev_snp feature including mshv and igvm feature.
## Use Cases
Cloud Hypervisor can be built to run on an MSHV root partition by enabling the mshv feature, e.g.:
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features mshv```
Cloud Hypervisor on MSHV can boot Linux guests using an IGVM file. IGVM feature depends on mshv for running legacy VMs.e.g.:
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features igvm```
For running confidential VMs on mshv, you will only need to enable sev_snp, it requires and enables mshv and igvm automatically, eg.:
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features sev_snp```

View File

@@ -25,7 +25,7 @@ $ perf record -g target/profiling/cloud-hypervisor \
--cpus boot=1 --memory size=1G \ --cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \ --cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \ --serial tty --console off \
--api-socket=/tmp/api1 --api-socket /tmp/api1
``` ```
For analysing the samples: For analysing the samples:
@@ -52,5 +52,5 @@ $ perf record --call-graph lbr --all-user --user-callchains -g target/release/cl
--cpus boot=1 --memory size=1G \ --cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \ --cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \ --serial tty --console off \
--api-socket=/tmp/api1 --api-socket /tmp/api1
``` ```

View File

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

View File

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

View File

@@ -50,14 +50,14 @@ The examples use __socat__ `>=1.7.4` to illustrate the VSOCK functionality. Howe
### Connecting from Host to Guest ### Connecting from Host to Guest
The guest starts to listen on the defined port: The host starts to listen on the defined port:
`$ socat - VSOCK-LISTEN:1234` `$ socat - VSOCK-LISTEN:1234`
Once the guest is listening, the host can send data: Once the host is listening, the guest can send data:
`echo -e "CONNECT 1234\\nHello from host!" | socat - UNIX-CONNECT:/tmp/ch.vsock `echo -e "CONNECT 1234\\nHello from host!" | socat - UNIX-CONNECT:/tmp/ch.vsock
Note the string `CONNECT <port>` prepended to the actual data. It is possible for the guest to start listening on different ports, thus the specific command is needed to instruct VSOCK to which listener the host wants to connect. It needs to be sent once per connection. Once the connection established, data transfers can take place directly. Note the string `CONNECT <port>` prepended to the actual data. It is possible for the guest to start listening on different ports, thus the specific command is needed to instruct VSOCK to which listener the host wants to connect. It needs to be sent once per connection. Once the connection established, data transfers can take place directly.
### Connecting from Guest to Host ### Connecting from Guest to Host

View File

@@ -49,7 +49,7 @@ qemu-system-x86_64 \
-m 4G \ -m 4G \
-bios ./$OVMF_DIR/OVMF_CODE.fd \ -bios ./$OVMF_DIR/OVMF_CODE.fd \
-cdrom ./$WIN_ISO_FILE \ -cdrom ./$WIN_ISO_FILE \
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom \ -drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom
-drive if=none,id=root,file=./$IMG_FILE \ -drive if=none,id=root,file=./$IMG_FILE \
-device virtio-blk-pci,drive=root,disable-legacy=on \ -device virtio-blk-pci,drive=root,disable-legacy=on \
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \ -device virtio-net-pci,netdev=mynet0,disable-legacy=on \

451
fuzz/Cargo.lock generated
View File

@@ -5,64 +5,16 @@ version = 3
[[package]] [[package]]
name = "acpi_tables" name = "acpi_tables"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#1a733bf690ccc10bdfeacad33e3c9f6cce0008fd" source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#1029d22777f07b04849234bbe756da34a6df2913"
dependencies = [ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "anstream"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.79" version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -73,9 +25,9 @@ dependencies = [
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
version = "1.3.2" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -105,6 +57,37 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "argh"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219"
dependencies = [
"argh_derive",
"argh_shared",
]
[[package]]
name = "argh_derive"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a"
dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn 2.0.23",
]
[[package]]
name = "argh_shared"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@@ -128,16 +111,16 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.1" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]] [[package]]
name = "block" name = "block"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"crc-any", "crc32c",
"io-uring", "io-uring",
"libc", "libc",
"log", "log",
@@ -156,15 +139,15 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "cc" name = "cc"
@@ -182,40 +165,13 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "37.0.0" version = "34.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
"clap", "argh",
"epoll", "epoll",
"event_monitor", "event_monitor",
"hypervisor", "hypervisor",
@@ -252,32 +208,25 @@ dependencies = [
"virtio-queue", "virtio-queue",
"vm-device", "vm-device",
"vm-memory", "vm-memory",
"vm-migration",
"vm-virtio", "vm-virtio",
"vmm", "vmm",
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]] [[package]]
name = "colorchoice" name = "crc32c"
version = "1.0.0" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" checksum = "d8f48d60e5b4d2c53d5c2b1d8a58c849a70ae5e5509b08a48d047e3b65714a74"
[[package]]
name = "crc-any"
version = "2.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01a5e1f881f6fb6099a7bdf949e946719fd4f1fefa56264890574febf0eb6d0"
dependencies = [ dependencies = [
"debug-helper", "rustc_version",
] ]
[[package]] [[package]]
name = "crc64" name = "crc64"
version = "2.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2707e3afba5e19b75d582d88bc79237418f2a2a2d673d01cf9b03633b46e98f3" checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]] [[package]]
name = "darling" name = "darling"
@@ -300,7 +249,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]] [[package]]
@@ -311,15 +260,9 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]]
name = "debug-helper"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
[[package]] [[package]]
name = "devices" name = "devices"
version = "0.1.0" version = "0.1.0"
@@ -327,7 +270,7 @@ dependencies = [
"acpi_tables", "acpi_tables",
"anyhow", "anyhow",
"arch", "arch",
"bitflags 2.4.1", "bitflags 2.3.3",
"byteorder", "byteorder",
"event_monitor", "event_monitor",
"hypervisor", "hypervisor",
@@ -351,7 +294,7 @@ version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.3.3",
"libc", "libc",
] ]
@@ -393,21 +336,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.30" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.11" version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -452,32 +395,32 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.27" version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.66" version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]] [[package]]
name = "kvm-bindings" name = "kvm-bindings"
version = "0.7.0" version = "0.6.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-live-upgrade-stable-37.x#f03fc575cdf20c3af9ca3d4d203f171943d95be4" source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.6.0-tdx#7d9ffb47e5b9b1989577258800a0f57c93f1445f"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
@@ -486,11 +429,10 @@ dependencies = [
[[package]] [[package]]
name = "kvm-ioctls" name = "kvm-ioctls"
version = "0.16.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9002dff009755414f22b962ec6ae6980b07d6d8b06e5297b1062019d72bd6a8c" checksum = "b8f8dc9c1896e5f144ec5d07169bc29f39a047686d29585a91f30489abfaeb6b"
dependencies = [ dependencies = [
"bitflags 2.4.1",
"kvm-bindings", "kvm-bindings",
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -498,9 +440,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.152" version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -515,18 +457,18 @@ dependencies = [
[[package]] [[package]]
name = "linux-loader" name = "linux-loader"
version = "0.11.0" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb68dd3452f25a8defaf0ae593509cff0c777683e4d8924f59ac7c5f89267a83" checksum = "1db6a725c8000971f83fa93ed7ee1b600e55a1471a2a653379d3c84f72effdcf"
dependencies = [ dependencies = [
"vm-memory", "vm-memory",
] ]
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.11" version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"scopeguard", "scopeguard",
@@ -541,7 +483,7 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#e75dfa1eeea23b69caa7407bc2c3a76d7b7262fb" source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#0d0fdcd50ea10c1b4777f9a958873fc848a5b7bb"
dependencies = [ dependencies = [
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -586,9 +528,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]] [[package]]
name = "option_parser" name = "option_parser"
@@ -634,23 +576,23 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.76" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -661,26 +603,34 @@ version = "0.1.0"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
"thiserror",
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.12" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad5e011230cad274d0532460c5ab69828ea47ae75681b42a841663efffaf794" checksum = "bce3a7139d2ee67d07538ee5dba997364fbc243e7e7143e96eb830c74bfaa082"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
] ]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.16" version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@@ -690,38 +640,44 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "seccompiler" name = "seccompiler"
version = "0.4.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "345a3e4dddf721a478089d4697b83c6c0a8f5bf16086f6c13397e4534eb6e2e5" checksum = "6f6575e3c2b3a0fe2ef3e53855b6a8dead7c29f783da5e123d378c8c6a89017e"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "serde" name = "semver"
version = "1.0.195" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "serde"
version = "1.0.168"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d614f89548720367ded108b3c843be93f3a341e22d5674ca0dd5cd57f34926af"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.195" version = "1.0.168"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" checksum = "d4fe589678c688e44177da4f27152ee2d190757271dc7f1d5b6b9f68d869d641"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.111" version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -730,9 +686,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.4.0" version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
dependencies = [ dependencies = [
"serde", "serde",
"serde_with_macros", "serde_with_macros",
@@ -740,14 +696,14 @@ dependencies = [
[[package]] [[package]]
name = "serde_with_macros" name = "serde_with_macros"
version = "3.4.0" version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]] [[package]]
@@ -775,9 +731,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.12.0" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]] [[package]]
name = "spin" name = "spin"
@@ -807,9 +763,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.47" version = "2.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -818,22 +774,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.56" version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.56" version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]
[[package]] [[package]]
@@ -866,26 +822,20 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.7.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
[[package]] [[package]]
name = "versionize" name = "versionize"
version = "0.2.0" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62929d59c7f6730b7298fcb363760550f4db6e353fbac4076d447d0e82799d6d" checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
dependencies = [ dependencies = [
"bincode", "bincode",
"crc64", "crc64",
@@ -900,8 +850,8 @@ dependencies = [
[[package]] [[package]]
name = "versionize_derive" name = "versionize_derive"
version = "0.1.6" version = "0.1.4"
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch-0.1.6#7906da996152e2d0ab08f5526440683bf3ca7834" source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -911,7 +861,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio-bindings" name = "vfio-bindings"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a" source = "git+https://github.com/rust-vmm/vfio?branch=main#847b0aa504ac6367efe42ba7e96a2d050737d4f0"
dependencies = [ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
@@ -919,7 +869,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio-ioctls" name = "vfio-ioctls"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a" source = "git+https://github.com/rust-vmm/vfio?branch=main#847b0aa504ac6367efe42ba7e96a2d050737d4f0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"kvm-bindings", "kvm-bindings",
@@ -935,7 +885,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio_user" name = "vfio_user"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#a1f6e52829e069b6d698b2cfeecac742e4653186" source = "git+https://github.com/rust-vmm/vfio-user?branch=main#2d96b90a7279547356ad8f83aaa3115ad5497302"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"libc", "libc",
@@ -951,11 +901,11 @@ dependencies = [
[[package]] [[package]]
name = "vhost" name = "vhost"
version = "0.10.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b64e816d0d49769fbfaa1494eb77cc2a3ddc526ead05c7f922cb7d64106286f" checksum = "61957aeb36daf0b00b87fff9c10dd28a161bd35ab157553d340d183b3d8756e6"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 1.3.2",
"libc", "libc",
"vm-memory", "vm-memory",
"vmm-sys-util", "vmm-sys-util",
@@ -963,9 +913,9 @@ dependencies = [
[[package]] [[package]]
name = "virtio-bindings" name = "virtio-bindings"
version = "0.2.2" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "878bcb1b2812a10c30d53b0ed054999de3d98f25ece91fc173973f9c57aaae86" checksum = "c18d7b74098a946470ea265b5bacbbf877abc3373021388454de0d47735a5b98"
[[package]] [[package]]
name = "virtio-devices" name = "virtio-devices"
@@ -1003,9 +953,9 @@ dependencies = [
[[package]] [[package]]
name = "virtio-queue" name = "virtio-queue"
version = "0.11.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3f69a13d6610db9312acbb438b0390362af905d37634a2106be70c0f734986d" checksum = "35aca00da06841bd99162c381ec65893cace23ca0fb89254302cfe4bec4c300f"
dependencies = [ dependencies = [
"log", "log",
"virtio-bindings", "virtio-bindings",
@@ -1042,9 +992,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
[[package]] [[package]]
name = "vm-memory" name = "vm-memory"
version = "0.14.0" version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74ffc42216c32c35f858fa4bfdcd9b61017dfd691e0240268fdc85dbf59e5459" checksum = "9dc276f0d00c17b9aeb584da0f1e1c673df0d183cc2539e3636ec8cbc5eae99b"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"libc", "libc",
@@ -1082,10 +1032,9 @@ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
"arch", "arch",
"bitflags 2.4.1", "bitflags 2.3.3",
"block", "block",
"cfg-if", "cfg-if",
"clap",
"devices", "devices",
"epoll", "epoll",
"event_monitor", "event_monitor",
@@ -1124,9 +1073,9 @@ dependencies = [
[[package]] [[package]]
name = "vmm-sys-util" name = "vmm-sys-util"
version = "0.12.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" checksum = "48b7b084231214f7427041e4220d77dfe726897a6d41fddee450696e66ff2a29"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"libc", "libc",
@@ -1142,9 +1091,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.89" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@@ -1152,24 +1101,24 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.89" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.89" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -1177,22 +1126,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.89" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.89" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]] [[package]]
name = "winapi" name = "winapi"
@@ -1216,77 +1165,11 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" checksum = "20707b61725734c595e840fb3704378a0cd2b9c74cc9e6e20724838fc6a1e2f9"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"zerocopy-derive", "zerocopy-derive",
@@ -1294,11 +1177,11 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.7.32" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" checksum = "56097d5b91d711293a42be9289403896b68654625021732067eac7a4ca388a1f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.23",
] ]

View File

@@ -8,26 +8,22 @@ edition = "2021"
[package.metadata] [package.metadata]
cargo-fuzz = true cargo-fuzz = true
[features]
igvm = []
[dependencies] [dependencies]
block = { path = "../block" } block = { path = "../block" }
devices = { path = "../devices" } devices = { path = "../devices" }
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.152" libc = "0.2.148"
libfuzzer-sys = "0.4.7" libfuzzer-sys = "0.4.7"
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] } linux-loader = { version = "0.9.1", features = ["elf", "bzimage", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
net_util = { path = "../net_util" } net_util = { path = "../net_util" }
once_cell = "1.19.0" once_cell = "1.18.0"
seccompiler = "0.4.0" seccompiler = "0.3.0"
virtio-devices = { path = "../virtio-devices" } virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.11.0" virtio-queue = "0.9.0"
vmm = { path = "../vmm" } vmm = { path = "../vmm" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.2"
vm-memory = "0.14.0" vm-memory = "0.12.2"
vm-migration = { path = "../vm-migration" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
@@ -35,8 +31,8 @@ vm-virtio = { path = "../vm-virtio" }
path = ".." path = ".."
[patch.crates-io] [patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x" } kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" } versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
# Prevent this from interfering with workspaces # Prevent this from interfering with workspaces
[workspace] [workspace]

View File

@@ -23,8 +23,6 @@ fuzz_target!(|bytes| {
kernel: None, kernel: None,
cmdline: Some(String::from_utf8_lossy(&bytes).to_string()), cmdline: Some(String::from_utf8_lossy(&bytes).to_string()),
initramfs: None, initramfs: None,
#[cfg(feature = "igvm")]
igvm: None,
}; };
let kernel_cmdline = match vmm::vm::Vm::generate_cmdline(&payload_config) { let kernel_cmdline = match vmm::vm::Vm::generate_cmdline(&payload_config) {
Ok(cmdline) => cmdline, Ok(cmdline) => cmdline,

View File

@@ -8,30 +8,28 @@ license = "Apache-2.0 OR BSD-3-Clause"
[features] [features]
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"] kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"]
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv", "iced-x86"] mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv", "iced-x86"]
sev_snp = ["igvm_parser", "igvm_defs"] sev_snp = []
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.75" anyhow = "1.0.75"
byteorder = "1.4.3" byteorder = "1.4.3"
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true } thiserror = "1.0.40"
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true }
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
kvm-ioctls = { version = "0.16.0", optional = true } kvm-ioctls = { version = "0.13.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-live-upgrade-stable-37.x", features = ["with-serde", "fam-wrappers"], optional = true } 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-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true} mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.168", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_with = { version = "3.4.0", default-features = false, features = ["macros"] } serde_with = { version = "3.0.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic"] } vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] } vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
thiserror = "1.0.52"
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86] [target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
optional = true optional = true
version = "1.20.0" version = "1.19.0"
default-features = false default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"] features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]

View File

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

View File

@@ -95,12 +95,12 @@ pub enum HypervisorCpuError {
#[error("Failed to get Msr entries: {0}")] #[error("Failed to get Msr entries: {0}")]
GetMsrEntries(#[source] anyhow::Error), GetMsrEntries(#[source] anyhow::Error),
/// ///
/// Setting multi-processing state error /// Setting MSR entries error
/// ///
#[error("Failed to set MP state: {0}")] #[error("Failed to set MP state: {0}")]
SetMpState(#[source] anyhow::Error), SetMpState(#[source] anyhow::Error),
/// ///
/// Getting multi-processing state error /// Getting Msr entries error
/// ///
#[error("Failed to get MP state: {0}")] #[error("Failed to get MP state: {0}")]
GetMpState(#[source] anyhow::Error), GetMpState(#[source] anyhow::Error),
@@ -257,21 +257,6 @@ pub enum HypervisorCpuError {
/// ///
#[error("Failed to set TSC frequency: {0}")] #[error("Failed to set TSC frequency: {0}")]
SetTscKhz(#[source] anyhow::Error), SetTscKhz(#[source] anyhow::Error),
///
/// Error reading value at given GPA
///
#[error("Failed to read from GPA: {0}")]
GpaRead(#[source] anyhow::Error),
///
/// Error writing value at given GPA
///
#[error("Failed to write to GPA: {0}")]
GpaWrite(#[source] anyhow::Error),
///
/// Error getting CPUID leaf
///
#[error("Failed to get CPUID entries: {0}")]
GetCpuidVales(#[source] anyhow::Error),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -482,17 +467,4 @@ pub trait Vcpu: Send + Sync {
fn set_tsc_khz(&self, _freq: u32) -> Result<()> { fn set_tsc_khz(&self, _freq: u32) -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(target_arch = "x86_64")]
///
/// X86 specific call to retrieve cpuid leaf
///
fn get_cpuid_values(
&self,
_function: u32,
_index: u32,
_xfem: u64,
_xss: u64,
) -> Result<[u32; 4]> {
unimplemented!()
}
} }

View File

@@ -47,7 +47,7 @@ use vmm_sys_util::eventfd::EventFd;
pub mod x86_64; pub mod x86_64;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86::{ use crate::arch::x86::{
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters, XsaveState, CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
NUM_IOAPIC_PINS, NUM_IOAPIC_PINS,
}; };
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -66,11 +66,13 @@ use kvm_bindings::{
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use x86_64::check_required_kvm_extensions; use x86_64::check_required_kvm_extensions;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState}; pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState, Xsave};
// aarch64 dependencies // aarch64 dependencies
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub mod aarch64; pub mod aarch64;
pub use kvm_bindings; pub use kvm_bindings;
#[cfg(feature = "tdx")]
use kvm_bindings::KVMIO;
pub use kvm_bindings::{ pub use kvm_bindings::{
kvm_clock_data, kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_guest_debug, kvm_clock_data, kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_guest_debug,
kvm_irq_routing, kvm_irq_routing_entry, kvm_mp_state, kvm_userspace_memory_region, kvm_irq_routing, kvm_irq_routing_entry, kvm_mp_state, kvm_userspace_memory_region,
@@ -84,8 +86,6 @@ use kvm_bindings::{
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
}; };
#[cfg(feature = "tdx")]
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
pub use kvm_ioctls; pub use kvm_ioctls;
pub use kvm_ioctls::{Cap, Kvm}; pub use kvm_ioctls::{Cap, Kvm};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@@ -169,52 +169,6 @@ pub struct TdxCapabilities {
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS], pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
} }
#[cfg(feature = "tdx")]
#[derive(Copy, Clone)]
pub struct KvmTdxExit {
pub type_: u32,
pub pad: u32,
pub u: KvmTdxExitU,
}
#[cfg(feature = "tdx")]
#[repr(C)]
#[derive(Copy, Clone)]
pub union KvmTdxExitU {
pub vmcall: KvmTdxExitVmcall,
}
#[cfg(feature = "tdx")]
#[repr(C)]
#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub struct KvmTdxExitVmcall {
pub type_: u64,
pub subfunction: u64,
pub reg_mask: u64,
pub in_r12: u64,
pub in_r13: u64,
pub in_r14: u64,
pub in_r15: u64,
pub in_rbx: u64,
pub in_rdi: u64,
pub in_rsi: u64,
pub in_r8: u64,
pub in_r9: u64,
pub in_rdx: u64,
pub status_code: u64,
pub out_r11: u64,
pub out_r12: u64,
pub out_r13: u64,
pub out_r14: u64,
pub out_r15: u64,
pub out_rbx: u64,
pub out_rdi: u64,
pub out_rsi: u64,
pub out_r8: u64,
pub out_r9: u64,
pub out_rdx: u64,
}
impl From<kvm_userspace_memory_region> for UserMemoryRegion { impl From<kvm_userspace_memory_region> for UserMemoryRegion {
fn from(region: kvm_userspace_memory_region) -> Self { fn from(region: kvm_userspace_memory_region) -> Self {
let mut flags = USER_MEMORY_REGION_READ; let mut flags = USER_MEMORY_REGION_READ;
@@ -315,7 +269,7 @@ impl From<CpuState> for VcpuKvmState {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
impl From<kvm_clock_data> for ClockData { impl From<kvm_clock_data> for ClockData {
fn from(d: kvm_clock_data) -> Self { fn from(d: kvm_clock_data) -> Self {
ClockData::Kvm(d.into()) ClockData::Kvm(d)
} }
} }
@@ -323,7 +277,7 @@ impl From<kvm_clock_data> for ClockData {
impl From<ClockData> for kvm_clock_data { impl From<ClockData> for kvm_clock_data {
fn from(ms: ClockData) -> Self { fn from(ms: ClockData) -> Self {
match ms { match ms {
ClockData::Kvm(s) => s.into(), ClockData::Kvm(s) => s,
/* Needed in case other hypervisors are enabled */ /* Needed in case other hypervisors are enabled */
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
_ => panic!("CpuState is not valid"), _ => panic!("CpuState is not valid"),
@@ -402,7 +356,6 @@ impl vm::Vm for KvmVm {
.set_identity_map_address(address) .set_identity_map_address(address)
.map_err(|e| vm::HypervisorVmError::SetIdentityMapAddress(e.into())) .map_err(|e| vm::HypervisorVmError::SetIdentityMapAddress(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the address of the three-page region in the VM's address space. /// Sets the address of the three-page region in the VM's address space.
@@ -412,7 +365,6 @@ impl vm::Vm for KvmVm {
.set_tss_address(offset) .set_tss_address(offset)
.map_err(|e| vm::HypervisorVmError::SetTssAddress(e.into())) .map_err(|e| vm::HypervisorVmError::SetTssAddress(e.into()))
} }
/// ///
/// Creates an in-kernel interrupt controller. /// Creates an in-kernel interrupt controller.
/// ///
@@ -421,7 +373,6 @@ impl vm::Vm for KvmVm {
.create_irq_chip() .create_irq_chip()
.map_err(|e| vm::HypervisorVmError::CreateIrq(e.into())) .map_err(|e| vm::HypervisorVmError::CreateIrq(e.into()))
} }
/// ///
/// Registers an event that will, when signaled, trigger the `gsi` IRQ. /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
/// ///
@@ -430,7 +381,6 @@ impl vm::Vm for KvmVm {
.register_irqfd(fd, gsi) .register_irqfd(fd, gsi)
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into())) .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))
} }
/// ///
/// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
/// ///
@@ -439,7 +389,6 @@ impl vm::Vm for KvmVm {
.unregister_irqfd(fd, gsi) .unregister_irqfd(fd, gsi)
.map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into())) .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))
} }
/// ///
/// Creates a VcpuFd object from a vcpu RawFd. /// Creates a VcpuFd object from a vcpu RawFd.
/// ///
@@ -462,7 +411,6 @@ impl vm::Vm for KvmVm {
}; };
Ok(Arc::new(vcpu)) Ok(Arc::new(vcpu))
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
/// ///
/// Creates a virtual GIC device. /// Creates a virtual GIC device.
@@ -472,7 +420,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::CreateVgic(anyhow!("Vgic error {:?}", e)))?; .map_err(|e| vm::HypervisorVmError::CreateVgic(anyhow!("Vgic error {:?}", e)))?;
Ok(Arc::new(Mutex::new(gic_device))) Ok(Arc::new(Mutex::new(gic_device)))
} }
/// ///
/// Registers an event to be signaled whenever a certain address is written to. /// Registers an event to be signaled whenever a certain address is written to.
/// ///
@@ -500,7 +447,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())) .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
} }
} }
/// ///
/// Unregisters an event from a certain address it has been previously registered to. /// Unregisters an event from a certain address it has been previously registered to.
/// ///
@@ -595,7 +541,6 @@ impl vm::Vm for KvmVm {
.set_gsi_routing(&irq_routing[0]) .set_gsi_routing(&irq_routing[0])
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into())) .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
} }
/// ///
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region /// Creates a memory region structure that can be used with {create/remove}_user_memory_region
/// ///
@@ -622,7 +567,6 @@ impl vm::Vm for KvmVm {
} }
.into() .into()
} }
/// ///
/// Creates a guest physical memory region. /// Creates a guest physical memory region.
/// ///
@@ -659,7 +603,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into())) .map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))
} }
} }
/// ///
/// Removes a guest physical memory region. /// Removes a guest physical memory region.
/// ///
@@ -678,7 +621,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into())) .map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))
} }
} }
/// ///
/// Returns the preferred CPU target type which can be emulated by KVM on underlying host. /// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
/// ///
@@ -688,7 +630,6 @@ impl vm::Vm for KvmVm {
.get_preferred_target(kvi) .get_preferred_target(kvi)
.map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into())) .map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn enable_split_irq(&self) -> vm::Result<()> { fn enable_split_irq(&self) -> vm::Result<()> {
// Create split irqchip // Create split irqchip
@@ -704,7 +645,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?; .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
Ok(()) Ok(())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn enable_sgx_attribute(&self, file: File) -> vm::Result<()> { fn enable_sgx_attribute(&self, file: File) -> vm::Result<()> {
let mut cap = kvm_enable_cap { let mut cap = kvm_enable_cap {
@@ -717,7 +657,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::EnableSgxAttribute(e.into()))?; .map_err(|e| vm::HypervisorVmError::EnableSgxAttribute(e.into()))?;
Ok(()) Ok(())
} }
/// Retrieve guest clock. /// Retrieve guest clock.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn get_clock(&self) -> vm::Result<ClockData> { fn get_clock(&self) -> vm::Result<ClockData> {
@@ -727,7 +666,6 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::GetClock(e.into()))? .map_err(|e| vm::HypervisorVmError::GetClock(e.into()))?
.into()) .into())
} }
/// Set guest clock. /// Set guest clock.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn set_clock(&self, data: &ClockData) -> vm::Result<()> { fn set_clock(&self, data: &ClockData) -> vm::Result<()> {
@@ -736,7 +674,6 @@ impl vm::Vm for KvmVm {
.set_clock(&data) .set_clock(&data)
.map_err(|e| vm::HypervisorVmError::SetClock(e.into())) .map_err(|e| vm::HypervisorVmError::SetClock(e.into()))
} }
/// Create a device that is used for passthrough /// Create a device that is used for passthrough
fn create_passthrough_device(&self) -> vm::Result<VfioDeviceFd> { fn create_passthrough_device(&self) -> vm::Result<VfioDeviceFd> {
let mut vfio_dev = kvm_create_device { let mut vfio_dev = kvm_create_device {
@@ -748,7 +685,6 @@ impl vm::Vm for KvmVm {
self.create_device(&mut vfio_dev) self.create_device(&mut vfio_dev)
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into())) .map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
} }
/// ///
/// Start logging dirty pages /// Start logging dirty pages
/// ///
@@ -890,7 +826,6 @@ impl vm::Vm for KvmVm {
) )
.map_err(vm::HypervisorVmError::InitMemRegionTdx) .map_err(vm::HypervisorVmError::InitMemRegionTdx)
} }
/// Downcast to the underlying KvmVm type /// Downcast to the underlying KvmVm type
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
@@ -957,9 +892,7 @@ pub enum KvmError {
#[error("Capability missing: {0:?}")] #[error("Capability missing: {0:?}")]
CapabilityMissing(Cap), CapabilityMissing(Cap),
} }
pub type KvmResult<T> = result::Result<T, KvmError>; pub type KvmResult<T> = result::Result<T, KvmError>;
impl KvmHypervisor { impl KvmHypervisor {
/// Create a hypervisor based on Kvm /// Create a hypervisor based on Kvm
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
@@ -973,7 +906,6 @@ impl KvmHypervisor {
Ok(Arc::new(KvmHypervisor { kvm: kvm_obj })) Ok(Arc::new(KvmHypervisor { kvm: kvm_obj }))
} }
/// Check if the hypervisor is available /// Check if the hypervisor is available
pub fn is_available() -> hypervisor::Result<bool> { pub fn is_available() -> hypervisor::Result<bool> {
match std::fs::metadata("/dev/kvm") { match std::fs::metadata("/dev/kvm") {
@@ -985,7 +917,6 @@ impl KvmHypervisor {
} }
} }
} }
/// Implementation of Hypervisor trait for KVM /// Implementation of Hypervisor trait for KVM
/// ///
/// # Examples /// # Examples
@@ -1004,7 +935,6 @@ impl hypervisor::Hypervisor for KvmHypervisor {
fn hypervisor_type(&self) -> HypervisorType { fn hypervisor_type(&self) -> HypervisorType {
HypervisorType::Kvm HypervisorType::Kvm
} }
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object /// Create a KVM vm object of a specific VM type and return the object as Vm trait object
/// ///
/// # Examples /// # Examples
@@ -1160,7 +1090,6 @@ impl hypervisor::Hypervisor for KvmHypervisor {
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32 self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
} }
} }
/// Vcpu struct for KVM /// Vcpu struct for KVM
pub struct KvmVcpu { pub struct KvmVcpu {
fd: VcpuFd, fd: VcpuFd,
@@ -1170,7 +1099,6 @@ pub struct KvmVcpu {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
hyperv_synic: AtomicBool, hyperv_synic: AtomicBool,
} }
/// Implementation of Vcpu trait for KVM /// Implementation of Vcpu trait for KVM
/// ///
/// # Examples /// # Examples
@@ -1195,7 +1123,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
.into()) .into())
} }
/// ///
/// Returns the vCPU general purpose registers. /// Returns the vCPU general purpose registers.
/// The `KVM_GET_REGS` ioctl is not available on AArch64, `KVM_GET_ONE_REG` /// The `KVM_GET_REGS` ioctl is not available on AArch64, `KVM_GET_ONE_REG`
@@ -1210,64 +1137,71 @@ impl cpu::Vcpu for KvmVcpu {
// These actually are the general-purpose registers of the Armv8-a // These actually are the general-purpose registers of the Armv8-a
// architecture (i.e x0-x30 if used as a 64bit register or w0-30 when used as a 32bit register). // architecture (i.e x0-x30 if used as a 64bit register or w0-30 when used as a 32bit register).
for i in 0..31 { for i in 0..31 {
let mut bytes = [0_u8; 8]; state.regs.regs[i] = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.regs.regs[i] = u64::from_le_bytes(bytes); .try_into()
.unwrap();
off += std::mem::size_of::<u64>(); off += std::mem::size_of::<u64>();
} }
// We are now entering the "Other register" section of the ARMv8-a architecture. // We are now entering the "Other register" section of the ARMv8-a architecture.
// First one, stack pointer. // First one, stack pointer.
let off = offset_of!(user_pt_regs, sp); let off = offset_of!(user_pt_regs, sp);
let mut bytes = [0_u8; 8]; state.regs.sp = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.regs.sp = u64::from_le_bytes(bytes); .try_into()
.unwrap();
// Second one, the program counter. // Second one, the program counter.
let off = offset_of!(user_pt_regs, pc); let off = offset_of!(user_pt_regs, pc);
let mut bytes = [0_u8; 8]; state.regs.pc = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.regs.pc = u64::from_le_bytes(bytes); .try_into()
.unwrap();
// Next is the processor state. // Next is the processor state.
let off = offset_of!(user_pt_regs, pstate); let off = offset_of!(user_pt_regs, pstate);
let mut bytes = [0_u8; 8]; state.regs.pstate = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.regs.pstate = u64::from_le_bytes(bytes); .try_into()
.unwrap();
// The stack pointer associated with EL1 // The stack pointer associated with EL1
let off = offset_of!(kvm_regs, sp_el1); let off = offset_of!(kvm_regs, sp_el1);
let mut bytes = [0_u8; 8]; state.sp_el1 = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.sp_el1 = u64::from_le_bytes(bytes); .try_into()
.unwrap();
// Exception Link Register for EL1, when taking an exception to EL1, this register // Exception Link Register for EL1, when taking an exception to EL1, this register
// holds the address to which to return afterwards. // holds the address to which to return afterwards.
let off = offset_of!(kvm_regs, elr_el1); let off = offset_of!(kvm_regs, elr_el1);
let mut bytes = [0_u8; 8]; state.elr_el1 = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.elr_el1 = u64::from_le_bytes(bytes); .try_into()
.unwrap();
// Saved Program Status Registers, there are 5 of them used in the kernel. // Saved Program Status Registers, there are 5 of them used in the kernel.
let mut off = offset_of!(kvm_regs, spsr); let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize { for i in 0..KVM_NR_SPSR as usize {
let mut bytes = [0_u8; 8]; state.spsr[i] = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.spsr[i] = u64::from_le_bytes(bytes); .try_into()
.unwrap();
off += std::mem::size_of::<u64>(); off += std::mem::size_of::<u64>();
} }
@@ -1275,32 +1209,32 @@ impl cpu::Vcpu for KvmVcpu {
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53 // https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs); let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 { for i in 0..32 {
let mut bytes = [0_u8; 16]; state.fp_regs.vregs[i] = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
state.fp_regs.vregs[i] = u128::from_le_bytes(bytes);
off += mem::size_of::<u128>(); off += mem::size_of::<u128>();
} }
// Floating-point Status Register // Floating-point Status Register
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
let mut bytes = [0_u8; 4]; state.fp_regs.fpsr = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.fp_regs.fpsr = u32::from_le_bytes(bytes); .try_into()
.unwrap();
// Floating-point Control Register // Floating-point Control Register
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr); let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
let mut bytes = [0_u8; 4]; state.fp_regs.fpcr = self
self.fd .fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes) .get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
state.fp_regs.fpcr = u32::from_le_bytes(bytes); .try_into()
.unwrap();
Ok(state) Ok(state)
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl. /// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl.
@@ -1326,7 +1260,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.regs[i].to_le_bytes(), state.regs.regs[i].into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
off += std::mem::size_of::<u64>(); off += std::mem::size_of::<u64>();
@@ -1336,7 +1270,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.sp.to_le_bytes(), state.regs.sp.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1344,7 +1278,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.pc.to_le_bytes(), state.regs.pc.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1352,7 +1286,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.regs.pstate.to_le_bytes(), state.regs.pstate.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1360,7 +1294,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.sp_el1.to_le_bytes(), state.sp_el1.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1368,7 +1302,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.elr_el1.to_le_bytes(), state.elr_el1.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1377,7 +1311,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off), arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
&state.spsr[i].to_le_bytes(), state.spsr[i].into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
off += std::mem::size_of::<u64>(); off += std::mem::size_of::<u64>();
@@ -1388,7 +1322,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U128, off), arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
&state.fp_regs.vregs[i].to_le_bytes(), state.fp_regs.vregs[i],
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
off += mem::size_of::<u128>(); off += mem::size_of::<u128>();
@@ -1398,7 +1332,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off), arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
&state.fp_regs.fpsr.to_le_bytes(), state.fp_regs.fpsr.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1406,7 +1340,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off), arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
&state.fp_regs.fpcr.to_le_bytes(), state.fp_regs.fpcr.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
Ok(()) Ok(())
@@ -1423,7 +1357,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl. /// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl.
@@ -1434,7 +1367,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_sregs(&sregs) .set_sregs(&sregs)
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the floating point state (FPU) from the vCPU. /// Returns the floating point state (FPU) from the vCPU.
@@ -1446,7 +1378,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct. /// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct.
@@ -1457,7 +1388,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_fpu(&fpu) .set_fpu(&fpu)
.map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call to setup the CPUID registers. /// X86 specific call to setup the CPUID registers.
@@ -1472,7 +1402,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_cpuid2(&kvm_cpuid) .set_cpuid2(&kvm_cpuid)
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call to enable HyperV SynIC /// X86 specific call to enable HyperV SynIC
@@ -1490,7 +1419,6 @@ impl cpu::Vcpu for KvmVcpu {
.enable_cap(&cap) .enable_cap(&cap)
.map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into())) .map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into()))
} }
/// ///
/// X86 specific call to retrieve the CPUID registers. /// X86 specific call to retrieve the CPUID registers.
/// ///
@@ -1505,7 +1433,6 @@ impl cpu::Vcpu for KvmVcpu {
Ok(v) Ok(v)
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
@@ -1517,7 +1444,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
@@ -1528,7 +1454,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_lapic(&klapic) .set_lapic(&klapic)
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the model-specific registers (MSR) for this vCPU. /// Returns the model-specific registers (MSR) for this vCPU.
@@ -1550,7 +1475,6 @@ impl cpu::Vcpu for KvmVcpu {
Ok(succ) Ok(succ)
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Setup the model-specific registers (MSR) for this vCPU. /// Setup the model-specific registers (MSR) for this vCPU.
@@ -1563,7 +1487,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_msrs(&kvm_msrs) .set_msrs(&kvm_msrs)
.map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
} }
/// ///
/// Returns the vcpu's current "multiprocessing state". /// Returns the vcpu's current "multiprocessing state".
/// ///
@@ -1574,7 +1497,6 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))?
.into()) .into())
} }
/// ///
/// Sets the vcpu's current "multiprocessing state". /// Sets the vcpu's current "multiprocessing state".
/// ///
@@ -1583,7 +1505,6 @@ impl cpu::Vcpu for KvmVcpu {
.set_mp_state(mp_state.into()) .set_mp_state(mp_state.into())
.map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Translates guest virtual address to guest physical address using the `KVM_TRANSLATE` ioctl. /// Translates guest virtual address to guest physical address using the `KVM_TRANSLATE` ioctl.
@@ -1602,7 +1523,6 @@ impl cpu::Vcpu for KvmVcpu {
_ => Ok((tr.physical_address, 0)), _ => Ok((tr.physical_address, 0)),
} }
} }
/// ///
/// Triggers the running of the current virtual CPU returning an exit reason. /// Triggers the running of the current virtual CPU returning an exit reason.
/// ///
@@ -1647,7 +1567,7 @@ impl cpu::Vcpu for KvmVcpu {
Ok(cpu::VmExit::Shutdown) Ok(cpu::VmExit::Shutdown)
} else { } else {
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unexpected system event with type 0x{:x}, flags 0x{:x?}", "Unexpected system event with type 0x{:x}, flags 0x{:x}",
event_type, event_type,
flags flags
))) )))
@@ -1694,7 +1614,6 @@ impl cpu::Vcpu for KvmVcpu {
}, },
} }
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Let the guest know that it has been paused, which prevents from /// Let the guest know that it has been paused, which prevents from
@@ -1712,7 +1631,6 @@ impl cpu::Vcpu for KvmVcpu {
Ok(()) Ok(())
} }
/// ///
/// Sets debug registers to set hardware breakpoints and/or enable single step. /// Sets debug registers to set hardware breakpoints and/or enable single step.
/// ///
@@ -1766,14 +1684,12 @@ impl cpu::Vcpu for KvmVcpu {
.set_guest_debug(&dbg) .set_guest_debug(&dbg)
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> { fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
self.fd self.fd
.vcpu_init(kvi) .vcpu_init(kvi)
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into())) .map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
} }
/// ///
/// Gets a list of the guest registers that are supported for the /// Gets a list of the guest registers that are supported for the
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls. /// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
@@ -1784,7 +1700,6 @@ impl cpu::Vcpu for KvmVcpu {
.get_reg_list(reg_list) .get_reg_list(reg_list)
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))
} }
/// ///
/// Gets the value of a system register /// Gets the value of a system register
/// ///
@@ -1811,13 +1726,13 @@ impl cpu::Vcpu for KvmVcpu {
| KVM_REG_ARM64_SYSREG_CRN_MASK | KVM_REG_ARM64_SYSREG_CRN_MASK
| KVM_REG_ARM64_SYSREG_CRM_MASK | KVM_REG_ARM64_SYSREG_CRM_MASK
| KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64); | KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64);
let mut bytes = [0_u8; 8]; Ok(self
self.fd .fd
.get_one_reg(id, &mut bytes) .get_one_reg(id)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
Ok(u64::from_le_bytes(bytes)) .try_into()
.unwrap())
} }
/// ///
/// Configure core registers for a given CPU. /// Configure core registers for a given CPU.
/// ///
@@ -1842,7 +1757,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate), arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
&PSTATE_FAULT_BITS_64.to_le_bytes(), PSTATE_FAULT_BITS_64.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1851,10 +1766,7 @@ impl cpu::Vcpu for KvmVcpu {
// Setting the PC (Processor Counter) to the current program address (kernel address). // Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset_of!(user_pt_regs, pc) + kreg_off; let pc = offset_of!(user_pt_regs, pc) + kreg_off;
self.fd self.fd
.set_one_reg( .set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip.into())
arm64_core_reg_id!(KVM_REG_SIZE_U64, pc),
&boot_ip.to_le_bytes(),
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB). // Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
@@ -1865,7 +1777,7 @@ impl cpu::Vcpu for KvmVcpu {
self.fd self.fd
.set_one_reg( .set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
&fdt_start.to_le_bytes(), fdt_start.into(),
) )
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
} }
@@ -1977,7 +1889,7 @@ impl cpu::Vcpu for KvmVcpu {
msr_entries msr_entries
}; };
let vcpu_events = self.get_vcpu_events()?.into(); let vcpu_events = self.get_vcpu_events()?;
let tsc_khz = self.tsc_khz()?; let tsc_khz = self.tsc_khz()?;
Ok(VcpuKvmState { Ok(VcpuKvmState {
@@ -1995,7 +1907,6 @@ impl cpu::Vcpu for KvmVcpu {
} }
.into()) .into())
} }
/// ///
/// Get the current AArch64 CPU state /// Get the current AArch64 CPU state
/// ///
@@ -2030,13 +1941,14 @@ impl cpu::Vcpu for KvmVcpu {
// register list, we are simply calling KVM_GET_ONE_REG. // register list, we are simply calling KVM_GET_ONE_REG.
let indices = reg_list.as_slice(); let indices = reg_list.as_slice();
for index in indices.iter() { for index in indices.iter() {
let mut bytes = [0_u8; 8];
self.fd
.get_one_reg(*index, &mut bytes)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
sys_regs.push(kvm_bindings::kvm_one_reg { sys_regs.push(kvm_bindings::kvm_one_reg {
id: *index, id: *index,
addr: u64::from_le_bytes(bytes), addr: self
.fd
.get_one_reg(*index)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
.try_into()
.unwrap(),
}); });
} }
@@ -2044,7 +1956,6 @@ impl cpu::Vcpu for KvmVcpu {
Ok(state.into()) Ok(state.into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Restore the previously saved CPU state /// Restore the previously saved CPU state
@@ -2130,11 +2041,10 @@ impl cpu::Vcpu for KvmVcpu {
} }
} }
self.set_vcpu_events(&state.vcpu_events.into())?; self.set_vcpu_events(&state.vcpu_events)?;
Ok(()) Ok(())
} }
/// ///
/// Restore the previously saved AArch64 CPU state /// Restore the previously saved AArch64 CPU state
/// ///
@@ -2146,7 +2056,7 @@ impl cpu::Vcpu for KvmVcpu {
// Set system registers // Set system registers
for reg in &state.sys_regs { for reg in &state.sys_regs {
self.fd self.fd
.set_one_reg(reg.id, &reg.addr.to_le_bytes()) .set_one_reg(reg.id, reg.addr.into())
.map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?;
} }
@@ -2178,12 +2088,7 @@ impl cpu::Vcpu for KvmVcpu {
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> { fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
let kvm_run = self.fd.get_kvm_run(); let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure // SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
as *mut KvmTdxExit))
.u
.vmcall
};
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND; tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
@@ -2207,19 +2112,13 @@ impl cpu::Vcpu for KvmVcpu {
fn set_tdx_status(&mut self, status: TdxExitStatus) { fn set_tdx_status(&mut self, status: TdxExitStatus) {
let kvm_run = self.fd.get_kvm_run(); let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure // SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
as *mut KvmTdxExit))
.u
.vmcall
};
tdx_vmcall.status_code = match status { tdx_vmcall.status_code = match status {
TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS, TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS,
TdxExitStatus::InvalidOperand => TDG_VP_VMCALL_INVALID_OPERAND, TdxExitStatus::InvalidOperand => TDG_VP_VMCALL_INVALID_OPERAND,
}; };
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Return the list of initial MSR entries for a VCPU /// Return the list of initial MSR entries for a VCPU
@@ -2245,7 +2144,6 @@ impl cpu::Vcpu for KvmVcpu {
] ]
.to_vec() .to_vec()
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn has_pmu_support(&self) -> bool { fn has_pmu_support(&self) -> bool {
let cpu_attr = kvm_bindings::kvm_device_attr { let cpu_attr = kvm_bindings::kvm_device_attr {
@@ -2256,7 +2154,6 @@ impl cpu::Vcpu for KvmVcpu {
}; };
self.fd.has_device_attr(&cpu_attr).is_ok() self.fd.has_device_attr(&cpu_attr).is_ok()
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn init_pmu(&self, irq: u32) -> cpu::Result<()> { fn init_pmu(&self, irq: u32) -> cpu::Result<()> {
let cpu_attr = kvm_bindings::kvm_device_attr { let cpu_attr = kvm_bindings::kvm_device_attr {
@@ -2319,25 +2216,20 @@ impl KvmVcpu {
/// ///
/// X86 specific call that returns the vcpu's current "xsave struct". /// X86 specific call that returns the vcpu's current "xsave struct".
/// ///
fn get_xsave(&self) -> cpu::Result<XsaveState> { fn get_xsave(&self) -> cpu::Result<Xsave> {
Ok(self self.fd
.fd
.get_xsave() .get_xsave()
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
.into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that sets the vcpu's current "xsave struct". /// X86 specific call that sets the vcpu's current "xsave struct".
/// ///
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> { fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
self.fd self.fd
.set_xsave(&xsave) .set_xsave(xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that returns the vcpu's current "xcrs". /// X86 specific call that returns the vcpu's current "xcrs".
@@ -2347,7 +2239,6 @@ impl KvmVcpu {
.get_xcrs() .get_xcrs()
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that sets the vcpu's current "xcrs". /// X86 specific call that sets the vcpu's current "xcrs".
@@ -2357,7 +2248,6 @@ impl KvmVcpu {
.set_xcrs(xcrs) .set_xcrs(xcrs)
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns currently pending exceptions, interrupts, and NMIs as well as related /// Returns currently pending exceptions, interrupts, and NMIs as well as related
@@ -2368,7 +2258,6 @@ impl KvmVcpu {
.get_vcpu_events() .get_vcpu_events()
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets pending exceptions, interrupts, and NMIs as well as related states /// Sets pending exceptions, interrupts, and NMIs as well as related states

View File

@@ -10,7 +10,7 @@
use crate::arch::x86::{ use crate::arch::x86::{
CpuIdEntry, DescriptorTable, FpuState, LapicState, MsrEntry, SegmentRegister, SpecialRegisters, CpuIdEntry, DescriptorTable, FpuState, LapicState, MsrEntry, SegmentRegister, SpecialRegisters,
StandardRegisters, XsaveState, CPUID_FLAG_VALID_INDEX, StandardRegisters, CPUID_FLAG_VALID_INDEX,
}; };
use crate::kvm::{Cap, Kvm, KvmError, KvmResult}; use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -22,8 +22,8 @@ pub use {
kvm_bindings::kvm_cpuid_entry2, kvm_bindings::kvm_dtable, kvm_bindings::kvm_fpu, kvm_bindings::kvm_cpuid_entry2, kvm_bindings::kvm_dtable, kvm_bindings::kvm_fpu,
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState, kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment, kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events_old as VcpuEvents, kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave, kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave,
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries, kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX, kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
}; };
@@ -64,7 +64,7 @@ pub struct VcpuKvmState {
pub sregs: kvm_sregs, pub sregs: kvm_sregs,
pub fpu: FpuState, pub fpu: FpuState,
pub lapic_state: LapicState, pub lapic_state: LapicState,
pub xsave: XsaveState, pub xsave: Xsave,
pub xcrs: ExtendedControlRegisters, pub xcrs: ExtendedControlRegisters,
pub mp_state: MpState, pub mp_state: MpState,
pub tsc_khz: Option<u32>, pub tsc_khz: Option<u32>,
@@ -330,18 +330,3 @@ impl From<MsrEntry> for kvm_msr_entry {
} }
} }
} }
impl From<kvm_xsave> for XsaveState {
fn from(s: kvm_xsave) -> Self {
Self { region: s.region }
}
}
impl From<XsaveState> for kvm_xsave {
fn from(s: XsaveState) -> Self {
Self {
region: s.region,
extra: Default::default(),
}
}
}

View File

@@ -162,7 +162,7 @@ pub enum CpuState {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub enum ClockData { pub enum ClockData {
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
Kvm(kvm_bindings::kvm_clock_data_old), Kvm(kvm_bindings::kvm_clock_data),
#[cfg(feature = "mshv")] #[cfg(feature = "mshv")]
Mshv, /* MSHV does not support ClockData yet */ Mshv, /* MSHV does not support ClockData yet */
} }

View File

@@ -20,21 +20,13 @@ use std::collections::HashMap;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use vfio_ioctls::VfioDeviceFd; use vfio_ioctls::VfioDeviceFd;
use vm::DataMatch; use vm::DataMatch;
#[cfg(feature = "sev_snp")]
mod snp_constants;
// x86_64 dependencies // x86_64 dependencies
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub mod x86_64; pub mod x86_64;
#[cfg(feature = "sev_snp")]
use snp_constants::*;
use crate::{ use crate::{
ClockData, CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion, ClockData, CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_WRITE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_WRITE,
}; };
#[cfg(feature = "sev_snp")]
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use x86_64::VcpuMshvState; pub use x86_64::VcpuMshvState;
@@ -200,7 +192,6 @@ impl MshvHypervisor {
} }
} }
} }
/// Implementation of Hypervisor trait for Mshv /// Implementation of Hypervisor trait for Mshv
/// ///
/// # Examples /// # Examples
@@ -243,33 +234,6 @@ impl hypervisor::Hypervisor for MshvHypervisor {
break; break;
} }
// Set additional partition property for SEV-SNP partition.
if mshv_vm_type == VmType::Snp {
let snp_policy = snp::get_default_snp_guest_policy();
let vmgexit_offloads = snp::get_default_vmgexit_offload_features();
// SAFETY: access union fields
unsafe {
debug!(
"Setting the partition isolation policy as: 0x{:x}",
snp_policy.as_uint64
);
fd.set_partition_property(
hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_POLICY,
snp_policy.as_uint64,
)
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
debug!(
"Setting the partition property to enable VMGEXIT offloads as : 0x{:x}",
vmgexit_offloads.as_uint64
);
fd.set_partition_property(
hv_partition_property_code_HV_PARTITION_PROPERTY_SEV_VMGEXIT_OFFLOADS,
vmgexit_offloads.as_uint64,
)
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
}
}
// Default Microsoft Hypervisor behavior for unimplemented MSR is to // Default Microsoft Hypervisor behavior for unimplemented MSR is to
// send a fault to the guest if it tries to access it. It is possible // send a fault to the guest if it tries to access it. It is possible
// to override this behavior with a more suitable option i.e., ignore // to override this behavior with a more suitable option i.e., ignore
@@ -339,8 +303,6 @@ pub struct MshvVcpu {
cpuid: Vec<CpuIdEntry>, cpuid: Vec<CpuIdEntry>,
msrs: Vec<MsrEntry>, msrs: Vec<MsrEntry>,
vm_ops: Option<Arc<dyn vm::VmOps>>, vm_ops: Option<Arc<dyn vm::VmOps>>,
#[cfg(feature = "sev_snp")]
vm_fd: Arc<VmFd>,
} }
/// Implementation of Vcpu trait for Microsoft Hypervisor /// Implementation of Vcpu trait for Microsoft Hypervisor
@@ -367,7 +329,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the vCPU general purpose registers. /// Sets the vCPU general purpose registers.
@@ -378,7 +339,6 @@ impl cpu::Vcpu for MshvVcpu {
.set_regs(&regs) .set_regs(&regs)
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the vCPU special registers. /// Returns the vCPU special registers.
@@ -390,7 +350,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the vCPU special registers. /// Sets the vCPU special registers.
@@ -401,7 +360,6 @@ impl cpu::Vcpu for MshvVcpu {
.set_sregs(&sregs) .set_sregs(&sregs)
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the floating point state (FPU) from the vCPU. /// Returns the floating point state (FPU) from the vCPU.
@@ -413,7 +371,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Set the floating point state (FPU) of a vCPU. /// Set the floating point state (FPU) of a vCPU.
@@ -446,7 +403,6 @@ impl cpu::Vcpu for MshvVcpu {
Ok(succ) Ok(succ)
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Setup the model-specific registers (MSR) for this vCPU. /// Setup the model-specific registers (MSR) for this vCPU.
@@ -468,7 +424,6 @@ impl cpu::Vcpu for MshvVcpu {
/* We always have SynIC enabled on MSHV */ /* We always have SynIC enabled on MSHV */
Ok(()) Ok(())
} }
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> { fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
let hv_message: hv_message = hv_message::default(); let hv_message: hv_message = hv_message::default();
@@ -629,427 +584,6 @@ impl cpu::Vcpu for MshvVcpu {
info.interrupt_vector.try_into().unwrap(), info.interrupt_vector.try_into().unwrap(),
)) ))
} }
#[cfg(feature = "sev_snp")]
hv_message_type_HVMSG_X64_SEV_VMGEXIT_INTERCEPT => {
let info = x.to_vmg_intercept_info().unwrap();
let ghcb_data = info.ghcb_msr >> GHCB_INFO_BIT_WIDTH;
let ghcb_msr = svm_ghcb_msr {
as_uint64: info.ghcb_msr,
};
// SAFETY: Accessing a union element from bindgen generated bindings.
let ghcb_op = unsafe { ghcb_msr.__bindgen_anon_2.ghcb_info() as u32 };
// Sanity check on the header fields before handling other operations.
assert!(info.header.intercept_access_type == HV_INTERCEPT_ACCESS_EXECUTE as u8);
match ghcb_op {
GHCB_INFO_HYP_FEATURE_REQUEST => {
// Pre-condition: GHCB data must be zero
assert!(ghcb_data == 0);
let mut ghcb_response = GHCB_INFO_HYP_FEATURE_RESPONSE as u64;
// Indicate support for basic SEV-SNP features
ghcb_response |=
(GHCB_HYP_FEATURE_SEV_SNP << GHCB_INFO_BIT_WIDTH) as u64;
// Indicate support for SEV-SNP AP creation
ghcb_response |= (GHCB_HYP_FEATURE_SEV_SNP_AP_CREATION
<< GHCB_INFO_BIT_WIDTH)
as u64;
debug!(
"GHCB_INFO_HYP_FEATURE_REQUEST: Supported features: {:0x}",
ghcb_response
);
let arr_reg_name_value =
[(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
}
GHCB_INFO_REGISTER_REQUEST => {
let mut ghcb_gpa = hv_x64_register_sev_ghcb::default();
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe {
ghcb_gpa.__bindgen_anon_1.set_enabled(1);
ghcb_gpa
.__bindgen_anon_1
.set_page_number(ghcb_msr.__bindgen_anon_2.gpa_page_number());
}
// SAFETY: Accessing a union element from bindgen generated bindings.
let reg_name_value = unsafe {
[(
hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA,
ghcb_gpa.as_uint64,
)]
};
set_registers_64!(self.fd, reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
let mut resp_ghcb_msr = svm_ghcb_msr::default();
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe {
resp_ghcb_msr
.__bindgen_anon_2
.set_ghcb_info(GHCB_INFO_REGISTER_RESPONSE as u64);
resp_ghcb_msr.__bindgen_anon_2.set_gpa_page_number(
ghcb_msr.__bindgen_anon_2.gpa_page_number(),
);
}
// SAFETY: Accessing a union element from bindgen generated bindings.
let reg_name_value = unsafe {
[(
hv_register_name_HV_X64_REGISTER_GHCB,
resp_ghcb_msr.as_uint64,
)]
};
set_registers_64!(self.fd, reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
}
GHCB_INFO_SEV_INFO_REQUEST => {
let sev_cpuid_function = 0x8000_001F;
let cpu_leaf = self
.fd
.get_cpuid_values(sev_cpuid_function, 0, 0, 0)
.unwrap();
let ebx = cpu_leaf[1];
// First 6-byte of EBX represents page table encryption bit number
let pbit_encryption = (ebx & 0x3f) as u8;
let mut ghcb_response = GHCB_INFO_SEV_INFO_RESPONSE as u64;
// GHCBData[63:48] specifies the maximum GHCB protocol version supported
ghcb_response |= (GHCB_PROTOCOL_VERSION_MAX as u64) << 48;
// GHCBData[47:32] specifies the minimum GHCB protocol version supported
ghcb_response |= (GHCB_PROTOCOL_VERSION_MIN as u64) << 32;
// GHCBData[31:24] specifies the SEV page table encryption bit number.
ghcb_response |= (pbit_encryption as u64) << 24;
let arr_reg_name_value =
[(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
}
GHCB_INFO_NORMAL => {
let exit_code =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_code as u32;
// SAFETY: Accessing a union element from bindgen generated bindings.
let pfn = unsafe { ghcb_msr.__bindgen_anon_2.gpa_page_number() };
let ghcb_gpa = pfn << GHCB_INFO_BIT_WIDTH;
match exit_code {
SVM_EXITCODE_HV_DOORBELL_PAGE => {
let exit_info1 =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32;
match exit_info1 {
SVM_NAE_HV_DOORBELL_PAGE_GET_PREFERRED => {
// Hypervisor does not have any preference for doorbell GPA.
let preferred_doorbell_gpa: u64 = 0xFFFFFFFFFFFFFFFF;
let mut swei2_rw_gpa_arg =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
swei2_rw_gpa_arg.data.copy_from_slice(
&preferred_doorbell_gpa.to_le_bytes(),
);
self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err(
|e| cpu::HypervisorCpuError::GpaWrite(e.into()),
)?;
}
SVM_NAE_HV_DOORBELL_PAGE_SET => {
let exit_info2 = info
.__bindgen_anon_2
.__bindgen_anon_1
.sw_exit_info2;
let mut ghcb_doorbell_gpa =
hv_x64_register_sev_hv_doorbell::default();
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe {
ghcb_doorbell_gpa.__bindgen_anon_1.set_enabled(1);
ghcb_doorbell_gpa
.__bindgen_anon_1
.set_page_number(exit_info2 >> PAGE_SHIFT);
}
// SAFETY: Accessing a union element from bindgen generated bindings.
let reg_names = unsafe {
[(
hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA,
ghcb_doorbell_gpa.as_uint64,
)]
};
set_registers_64!(self.fd, reg_names).map_err(|e| {
cpu::HypervisorCpuError::SetRegister(e.into())
})?;
let mut swei2_rw_gpa_arg =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
swei2_rw_gpa_arg.data[0..8]
.copy_from_slice(&exit_info2.to_le_bytes());
self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err(
|e| cpu::HypervisorCpuError::GpaWrite(e.into()),
)?;
// Clear the SW_EXIT_INFO1 register to indicate no error
let mut swei1_rw_gpa_arg =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd.gpa_write(&mut swei1_rw_gpa_arg).map_err(
|e| cpu::HypervisorCpuError::GpaWrite(e.into()),
)?;
}
SVM_NAE_HV_DOORBELL_PAGE_QUERY => {
let mut reg_assocs = [ hv_register_assoc {
name: hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA,
..Default::default()
} ];
self.fd.get_reg(&mut reg_assocs).unwrap();
// SAFETY: Accessing a union element from bindgen generated bindings.
let doorbell_gpa = unsafe { reg_assocs[0].value.reg64 };
let mut swei2_rw_gpa_arg =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
swei2_rw_gpa_arg
.data
.copy_from_slice(&doorbell_gpa.to_le_bytes());
self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err(
|e| cpu::HypervisorCpuError::GpaWrite(e.into()),
)?;
}
SVM_NAE_HV_DOORBELL_PAGE_CLEAR => {
let mut swei2_rw_gpa_arg =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err(
|e| cpu::HypervisorCpuError::GpaWrite(e.into()),
)?;
}
_ => {
panic!(
"SVM_EXITCODE_HV_DOORBELL_PAGE: Unhandled exit code: {:0x}",
exit_info1
);
}
}
}
SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST => {
warn!("Fetching extended guest request is not supported");
// Extended guest request is not supported by the Hypervisor
// Returning the error to the guest
// 0x6 means `The NAE event was not valid`
// Reference: GHCB Spec, page 42
let value: u64 = 0x6;
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
swei2_rw_gpa_arg.data.copy_from_slice(&value.to_le_bytes());
self.fd
.gpa_write(&mut swei2_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
}
SVM_EXITCODE_IOIO_PROT => {
let exit_info1 =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32;
let port_info = hv_sev_vmgexit_port_info {
as_uint32: exit_info1,
};
let port =
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe { port_info.__bindgen_anon_1.intercepted_port() };
let mut len = 4;
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe {
if port_info.__bindgen_anon_1.operand_size_16bit() == 1 {
len = 2;
} else if port_info.__bindgen_anon_1.operand_size_8bit()
== 1
{
len = 1;
}
}
let is_write =
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe { port_info.__bindgen_anon_1.access_type() == 0 };
let mut rax_rw_gpa_arg: mshv_read_write_gpa =
mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_RAX_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd
.gpa_read(&mut rax_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?;
if is_write {
if let Some(vm_ops) = &self.vm_ops {
vm_ops
.pio_write(
port.into(),
&rax_rw_gpa_arg.data[0..len],
)
.map_err(|e| {
cpu::HypervisorCpuError::RunVcpu(e.into())
})?;
}
} else {
if let Some(vm_ops) = &self.vm_ops {
vm_ops
.pio_read(
port.into(),
&mut rax_rw_gpa_arg.data[0..len],
)
.map_err(|e| {
cpu::HypervisorCpuError::RunVcpu(e.into())
})?;
}
self.fd.gpa_write(&mut rax_rw_gpa_arg).map_err(|e| {
cpu::HypervisorCpuError::GpaWrite(e.into())
})?;
}
// Clear the SW_EXIT_INFO1 register to indicate no error
let mut swei1_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd
.gpa_write(&mut swei1_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
}
SVM_EXITCODE_MMIO_READ => {
let src_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
let dst_gpa = info.__bindgen_anon_2.__bindgen_anon_1.sw_scratch;
let data_len =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
as usize;
// Sanity check to make sure data len is within supported range.
assert!(data_len <= 0x8);
let mut data: Vec<u8> = vec![0; data_len];
if let Some(vm_ops) = &self.vm_ops {
vm_ops.mmio_read(src_gpa, &mut data[0..data_len]).map_err(
|e| cpu::HypervisorCpuError::RunVcpu(e.into()),
)?;
}
let mut arg: mshv_read_write_gpa =
mshv_bindings::mshv_read_write_gpa {
base_gpa: dst_gpa,
byte_count: data_len as u32,
..Default::default()
};
arg.data[0..data_len].copy_from_slice(&data);
self.fd
.gpa_write(&mut arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
}
SVM_EXITCODE_MMIO_WRITE => {
let dst_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
let src_gpa = info.__bindgen_anon_2.__bindgen_anon_1.sw_scratch;
let data_len =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
as usize;
// Sanity check to make sure data len is within supported range.
assert!(data_len <= 0x8);
let mut arg: mshv_read_write_gpa =
mshv_bindings::mshv_read_write_gpa {
base_gpa: src_gpa,
byte_count: data_len as u32,
..Default::default()
};
self.fd
.gpa_read(&mut arg)
.map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?;
if let Some(vm_ops) = &self.vm_ops {
vm_ops
.mmio_write(dst_gpa, &arg.data[0..data_len])
.map_err(|e| {
cpu::HypervisorCpuError::RunVcpu(e.into())
})?;
}
}
SVM_EXITCODE_SNP_GUEST_REQUEST => {
let req_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
let rsp_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
let mshv_psp_req =
mshv_issue_psp_guest_request { req_gpa, rsp_gpa };
self.vm_fd
.psp_issue_guest_request(&mshv_psp_req)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
debug!(
"SNP guest request: req_gpa {:0x} rsp_gpa {:0x}",
req_gpa, rsp_gpa
);
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd
.gpa_write(&mut swei2_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
}
SVM_EXITCODE_SNP_AP_CREATION => {
let vmsa_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
let apic_id =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 >> 32;
debug!(
"SNP AP CREATE REQUEST with VMSA GPA {:0x}, and APIC ID {:?}",
vmsa_gpa, apic_id
);
let mshv_ap_create_req = mshv_sev_snp_ap_create {
vp_id: apic_id,
vmsa_gpa,
};
self.vm_fd
.sev_snp_ap_create(&mshv_ap_create_req)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
byte_count: std::mem::size_of::<u64>() as u32,
..Default::default()
};
self.fd
.gpa_write(&mut swei2_rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
}
_ => panic!(
"GHCB_INFO_NORMAL: Unhandled exit code: {:0x}",
exit_code
),
}
}
_ => panic!("Unsupported VMGEXIT operation: {:0x}", ghcb_op),
}
Ok(cpu::VmExit::Ignore)
}
exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!( exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unhandled VCPU exit {:?}", "Unhandled VCPU exit {:?}",
exit exit
@@ -1065,7 +599,6 @@ impl cpu::Vcpu for MshvVcpu {
}, },
} }
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call to setup the CPUID registers. /// X86 specific call to setup the CPUID registers.
@@ -1079,7 +612,6 @@ impl cpu::Vcpu for MshvVcpu {
.register_intercept_result_cpuid(&mshv_cpuid) .register_intercept_result_cpuid(&mshv_cpuid)
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call to retrieve the CPUID registers. /// X86 specific call to retrieve the CPUID registers.
@@ -1087,23 +619,6 @@ impl cpu::Vcpu for MshvVcpu {
fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> { fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
Ok(self.cpuid.clone()) Ok(self.cpuid.clone())
} }
#[cfg(target_arch = "x86_64")]
///
/// X86 specific call to retrieve cpuid leaf
///
fn get_cpuid_values(
&self,
function: u32,
index: u32,
xfem: u64,
xss: u64,
) -> cpu::Result<[u32; 4]> {
self.fd
.get_cpuid_values(function, index, xfem, xss)
.map_err(|e| cpu::HypervisorCpuError::GetCpuidVales(e.into()))
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
@@ -1115,7 +630,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))? .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
@@ -1126,21 +640,18 @@ impl cpu::Vcpu for MshvVcpu {
.set_lapic(&lapic) .set_lapic(&lapic)
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
} }
/// ///
/// Returns the vcpu's current "multiprocessing state". /// Returns the vcpu's current "multiprocessing state".
/// ///
fn get_mp_state(&self) -> cpu::Result<MpState> { fn get_mp_state(&self) -> cpu::Result<MpState> {
Ok(MpState::Mshv) Ok(MpState::Mshv)
} }
/// ///
/// Sets the vcpu's current "multiprocessing state". /// Sets the vcpu's current "multiprocessing state".
/// ///
fn set_mp_state(&self, _mp_state: MpState) -> cpu::Result<()> { fn set_mp_state(&self, _mp_state: MpState) -> cpu::Result<()> {
Ok(()) Ok(())
} }
/// ///
/// Set CPU state /// Set CPU state
/// ///
@@ -1166,7 +677,6 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
Ok(()) Ok(())
} }
/// ///
/// Get CPU State /// Get CPU State
/// ///
@@ -1203,7 +713,6 @@ impl cpu::Vcpu for MshvVcpu {
} }
.into()) .into())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Translate guest virtual address to guest physical address /// Translate guest virtual address to guest physical address
@@ -1220,7 +729,6 @@ impl cpu::Vcpu for MshvVcpu {
Ok((gpa, result_code)) Ok((gpa, result_code))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Return the list of initial MSR entries for a VCPU /// Return the list of initial MSR entries for a VCPU
@@ -1253,7 +761,6 @@ impl MshvVcpu {
.get_xsave() .get_xsave()
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that sets the vcpu's current "xsave struct". /// X86 specific call that sets the vcpu's current "xsave struct".
@@ -1263,7 +770,6 @@ impl MshvVcpu {
.set_xsave(xsave) .set_xsave(xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that returns the vcpu's current "xcrs". /// X86 specific call that returns the vcpu's current "xcrs".
@@ -1273,7 +779,6 @@ impl MshvVcpu {
.get_xcrs() .get_xcrs()
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// X86 specific call that sets the vcpu's current "xcrs". /// X86 specific call that sets the vcpu's current "xcrs".
@@ -1283,7 +788,6 @@ impl MshvVcpu {
.set_xcrs(xcrs) .set_xcrs(xcrs)
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Returns currently pending exceptions, interrupts, and NMIs as well as related /// Returns currently pending exceptions, interrupts, and NMIs as well as related
@@ -1294,7 +798,6 @@ impl MshvVcpu {
.get_vcpu_events() .get_vcpu_events()
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets pending exceptions, interrupts, and NMIs as well as related states /// Sets pending exceptions, interrupts, and NMIs as well as related states
@@ -1474,7 +977,6 @@ impl vm::Vm for MshvVm {
fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> { fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> {
Ok(()) Ok(())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Sets the address of the three-page region in the VM's address space. /// Sets the address of the three-page region in the VM's address space.
@@ -1482,14 +984,12 @@ impl vm::Vm for MshvVm {
fn set_tss_address(&self, _offset: usize) -> vm::Result<()> { fn set_tss_address(&self, _offset: usize) -> vm::Result<()> {
Ok(()) Ok(())
} }
/// ///
/// Creates an in-kernel interrupt controller. /// Creates an in-kernel interrupt controller.
/// ///
fn create_irq_chip(&self) -> vm::Result<()> { fn create_irq_chip(&self) -> vm::Result<()> {
Ok(()) Ok(())
} }
/// ///
/// Registers an event that will, when signaled, trigger the `gsi` IRQ. /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
/// ///
@@ -1502,7 +1002,6 @@ impl vm::Vm for MshvVm {
Ok(()) Ok(())
} }
/// ///
/// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
/// ///
@@ -1515,7 +1014,6 @@ impl vm::Vm for MshvVm {
Ok(()) Ok(())
} }
/// ///
/// Creates a VcpuFd object from a vcpu RawFd. /// Creates a VcpuFd object from a vcpu RawFd.
/// ///
@@ -1534,22 +1032,17 @@ impl vm::Vm for MshvVm {
cpuid: Vec::new(), cpuid: Vec::new(),
msrs: self.msrs.clone(), msrs: self.msrs.clone(),
vm_ops, vm_ops,
#[cfg(feature = "sev_snp")]
vm_fd: self.fd.clone(),
}; };
Ok(Arc::new(vcpu)) Ok(Arc::new(vcpu))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn enable_split_irq(&self) -> vm::Result<()> { fn enable_split_irq(&self) -> vm::Result<()> {
Ok(()) Ok(())
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> { fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
Ok(()) Ok(())
} }
fn register_ioevent( fn register_ioevent(
&self, &self,
fd: &EventFd, fd: &EventFd,
@@ -1580,7 +1073,6 @@ impl vm::Vm for MshvVm {
.map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())) .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
} }
} }
/// Unregister an event from a certain address it has been previously registered to. /// Unregister an event from a certain address it has been previously registered to.
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> { fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
let addr = &mshv_ioctls::IoEventAddress::from(*addr); let addr = &mshv_ioctls::IoEventAddress::from(*addr);
@@ -1705,7 +1197,6 @@ impl vm::Vm for MshvVm {
.set_msi_routing(&msi_routing[0]) .set_msi_routing(&msi_routing[0])
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into())) .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
} }
/// ///
/// Start logging dirty pages /// Start logging dirty pages
/// ///
@@ -1714,7 +1205,6 @@ impl vm::Vm for MshvVm {
.enable_dirty_page_tracking() .enable_dirty_page_tracking()
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into())) .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
} }
/// ///
/// Stop logging dirty pages /// Stop logging dirty pages
/// ///
@@ -1733,7 +1223,6 @@ impl vm::Vm for MshvVm {
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?; .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
Ok(()) Ok(())
} }
/// ///
/// Get dirty pages bitmap (one bit per page) /// Get dirty pages bitmap (one bit per page)
/// ///
@@ -1746,115 +1235,18 @@ impl vm::Vm for MshvVm {
) )
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into())) .map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
} }
/// Retrieve guest clock. /// Retrieve guest clock.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn get_clock(&self) -> vm::Result<ClockData> { fn get_clock(&self) -> vm::Result<ClockData> {
Ok(ClockData::Mshv) Ok(ClockData::Mshv)
} }
/// Set guest clock. /// Set guest clock.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn set_clock(&self, _data: &ClockData) -> vm::Result<()> { fn set_clock(&self, _data: &ClockData) -> vm::Result<()> {
Ok(()) Ok(())
} }
/// Downcast to the underlying MshvVm type /// Downcast to the underlying MshvVm type
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
/// Initialize the SEV-SNP VM
#[cfg(feature = "sev_snp")]
fn sev_snp_init(&self) -> vm::Result<()> {
self.fd
.set_partition_property(
hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_STATE,
hv_partition_isolation_state_HV_PARTITION_ISOLATION_SECURE as u64,
)
.map_err(|e| vm::HypervisorVmError::InitializeSevSnp(e.into()))
}
///
/// Importing isolated pages, these pages will be used
/// for the PSP(Platform Security Processor) measurement.
#[cfg(feature = "sev_snp")]
fn import_isolated_pages(
&self,
page_type: u32,
page_size: u32,
pages: &[u64],
) -> vm::Result<()> {
if pages.is_empty() {
return Ok(());
}
let mut isolated_pages =
vec_with_array_field::<mshv_import_isolated_pages, u64>(pages.len());
isolated_pages[0].num_pages = pages.len() as u64;
isolated_pages[0].page_type = page_type;
isolated_pages[0].page_size = page_size;
// SAFETY: isolated_pages initialized with pages.len() and now it is being turned into
// pages_slice with pages.len() again. It is guaranteed to be large enough to hold
// everything from pages.
unsafe {
let pages_slice: &mut [u64] = isolated_pages[0].page_number.as_mut_slice(pages.len());
pages_slice.copy_from_slice(pages);
}
self.fd
.import_isolated_pages(&isolated_pages[0])
.map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into()))
}
///
/// Complete isolated import, telling the hypervisor that
/// importing the pages to guest memory is complete.
///
#[cfg(feature = "sev_snp")]
fn complete_isolated_import(
&self,
snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
host_data: &[u8],
id_block_enabled: u8,
) -> vm::Result<()> {
let mut auth_info = hv_snp_id_auth_info {
id_key_algorithm: snp_id_block.id_key_algorithm,
auth_key_algorithm: snp_id_block.author_key_algorithm,
..Default::default()
};
// Each of r/s component is 576 bits long
auth_info.id_block_signature[..SIG_R_COMPONENT_SIZE_IN_BYTES]
.copy_from_slice(snp_id_block.id_key_signature.r_comp.as_ref());
auth_info.id_block_signature
[SIG_R_COMPONENT_SIZE_IN_BYTES..SIG_R_AND_S_COMPONENT_SIZE_IN_BYTES]
.copy_from_slice(snp_id_block.id_key_signature.s_comp.as_ref());
auth_info.id_key[..ECDSA_CURVE_ID_SIZE_IN_BYTES]
.copy_from_slice(snp_id_block.id_public_key.curve.to_le_bytes().as_ref());
auth_info.id_key[ECDSA_SIG_X_COMPONENT_START..ECDSA_SIG_X_COMPONENT_END]
.copy_from_slice(snp_id_block.id_public_key.qx.as_ref());
auth_info.id_key[ECDSA_SIG_Y_COMPONENT_START..ECDSA_SIG_Y_COMPONENT_END]
.copy_from_slice(snp_id_block.id_public_key.qy.as_ref());
let data = mshv_complete_isolated_import {
import_data: hv_partition_complete_isolated_import_data {
psp_parameters: hv_psp_launch_finish_data {
id_block: hv_snp_id_block {
launch_digest: snp_id_block.ld,
family_id: snp_id_block.family_id,
image_id: snp_id_block.image_id,
version: snp_id_block.version,
guest_svn: snp_id_block.guest_svn,
policy: get_default_snp_guest_policy(),
},
id_auth_info: auth_info,
host_data: host_data[0..32].try_into().unwrap(),
id_block_enabled,
author_key_enabled: 0,
},
},
};
self.fd
.complete_isolated_import(&data)
.map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into()))
}
} }

View File

@@ -1,24 +0,0 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
// Copyright © 2020, Microsoft Corporation
//
// Reference: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf
// Chapter 10
pub const SIG_R_COMPONENT_SIZE_IN_BYTES: usize = 72;
pub const SIG_R_AND_S_COMPONENT_SIZE_IN_BYTES: usize = 144;
pub const ECDSA_CURVE_ID_SIZE_IN_BYTES: usize = 4;
pub const ECDSA_SIG_X_COMPONENT_SIZE_IN_BYTES: usize = 72;
pub const ECDSA_SIG_Y_COMPONENT_SIZE_IN_BYTES: usize = 72;
pub const ECDSA_SIG_X_COMPONENT_START: usize = ECDSA_CURVE_ID_SIZE_IN_BYTES;
pub const ECDSA_SIG_X_COMPONENT_END: usize =
ECDSA_SIG_X_COMPONENT_START + ECDSA_SIG_X_COMPONENT_SIZE_IN_BYTES;
pub const ECDSA_SIG_Y_COMPONENT_START: usize = ECDSA_SIG_X_COMPONENT_END;
pub const ECDSA_SIG_Y_COMPONENT_END: usize =
ECDSA_SIG_X_COMPONENT_END + ECDSA_SIG_Y_COMPONENT_SIZE_IN_BYTES;
// These constants are derived from GHCB spec Sect. 2.6 Table 3 GHCB Layout
// Link: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf
pub const GHCB_RAX_OFFSET: u64 = 0x01F8;
pub const GHCB_SW_EXITINFO1_OFFSET: u64 = 0x398;
pub const GHCB_SW_EXITINFO2_OFFSET: u64 = 0x3A0;

View File

@@ -19,8 +19,6 @@ use crate::cpu::Vcpu;
use crate::ClockData; use crate::ClockData;
use crate::UserMemoryRegion; use crate::UserMemoryRegion;
use crate::{IoEventAddress, IrqRoutingEntry}; use crate::{IoEventAddress, IrqRoutingEntry};
#[cfg(feature = "sev_snp")]
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
use std::any::Any; use std::any::Any;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::fs::File; use std::fs::File;
@@ -192,13 +190,6 @@ pub enum HypervisorVmError {
#[error("Failed to assert virtual Interrupt: {0}")] #[error("Failed to assert virtual Interrupt: {0}")]
AsserttVirtualInterrupt(#[source] anyhow::Error), AsserttVirtualInterrupt(#[source] anyhow::Error),
#[cfg(feature = "sev_snp")]
///
/// Error initializing SEV-SNP on the VM
///
#[error("Failed to initialize SEV-SNP: {0}")]
InitializeSevSnp(#[source] std::io::Error),
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
/// ///
/// Error initializing TDX on the VM /// Error initializing TDX on the VM
@@ -222,15 +213,6 @@ pub enum HypervisorVmError {
/// ///
#[error("Failed to create Vgic: {0}")] #[error("Failed to create Vgic: {0}")]
CreateVgic(#[source] anyhow::Error), CreateVgic(#[source] anyhow::Error),
///
/// Import isolated pages error
///
#[error("Failed to import isolated pages: {0}")]
ImportIsolatedPages(#[source] anyhow::Error),
/// Failed to complete isolated import
///
#[error("Failed to complete isolated import: {0}")]
CompleteIsolatedImport(#[source] anyhow::Error),
} }
/// ///
/// Result type for returning from a function /// Result type for returning from a function
@@ -342,11 +324,6 @@ pub trait Vm: Send + Sync + Any {
fn stop_dirty_log(&self) -> Result<()>; fn stop_dirty_log(&self) -> Result<()>;
/// Get dirty pages bitmap /// Get dirty pages bitmap
fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>; fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>;
#[cfg(feature = "sev_snp")]
/// Initialize SEV-SNP on this VM
fn sev_snp_init(&self) -> Result<()> {
unimplemented!()
}
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
/// Initialize TDX on this VM /// Initialize TDX on this VM
fn tdx_init(&self, _cpuid: &[CpuIdEntry], _max_vcpus: u32) -> Result<()> { fn tdx_init(&self, _cpuid: &[CpuIdEntry], _max_vcpus: u32) -> Result<()> {
@@ -370,26 +347,6 @@ pub trait Vm: Send + Sync + Any {
} }
/// Downcast to the underlying hypervisor VM type /// Downcast to the underlying hypervisor VM type
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
/// Import the isolated pages
#[cfg(feature = "sev_snp")]
fn import_isolated_pages(
&self,
_page_type: u32,
_page_size: u32,
_pages: &[u64],
) -> Result<()> {
unimplemented!()
}
/// Complete the isolated import
#[cfg(feature = "sev_snp")]
fn complete_isolated_import(
&self,
_snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
_host_data: &[u8],
_id_block_enabled: u8,
) -> Result<()> {
unimplemented!()
}
} }
pub trait VmOps: Send + Sync { pub trait VmOps: Send + Sync {

View File

@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"

View File

@@ -8,18 +8,18 @@ edition = "2021"
epoll = "4.3.3" epoll = "4.3.3"
getrandom = "0.2.10" getrandom = "0.2.10"
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
serde = "1.0.168" serde = "1.0.168"
thiserror = "1.0.52" thiserror = "1.0.40"
versionize = "0.2.0" versionize = "0.1.10"
versionize_derive = "0.1.6" versionize_derive = "0.1.4"
virtio-bindings = "0.2.0" virtio-bindings = "0.2.0"
virtio-queue = "0.11.0" virtio-queue = "0.9.0"
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"
[dev-dependencies] [dev-dependencies]
once_cell = "1.18.0" once_cell = "1.18.0"

View File

@@ -72,10 +72,6 @@ pub fn open_tap(
let mut taps: Vec<Tap> = Vec::new(); let mut taps: Vec<Tap> = Vec::new();
let mut ifname: String = String::new(); let mut ifname: String = String::new();
let vnet_hdr_size = vnet_hdr_len() as i32; let vnet_hdr_size = vnet_hdr_len() as i32;
// Check if the given interface exists before we create it.
let tap_existed = if_name.map_or(false, |n| {
Path::new(&format!("/sys/class/net/{n}")).exists()
});
// In case the tap interface already exists, check if the number of // In case the tap interface already exists, check if the number of
// queues is appropriate. The tap might not support multiqueue while // queues is appropriate. The tap might not support multiqueue while
@@ -91,19 +87,11 @@ pub fn open_tap(
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?, Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?, None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
}; };
// Don't overwrite ip configuration of existing interfaces: if let Some(ip) = ip_addr {
if !tap_existed { tap.set_ip_addr(ip).map_err(Error::TapSetIp)?;
if let Some(ip) = ip_addr { }
tap.set_ip_addr(ip).map_err(Error::TapSetIp)?; if let Some(mask) = netmask {
} tap.set_netmask(mask).map_err(Error::TapSetNetmask)?;
if let Some(mask) = netmask {
tap.set_netmask(mask).map_err(Error::TapSetNetmask)?;
}
} else {
warn!(
"Tap {} already exists. IP configuration will not be overwritten.",
if_name.unwrap_or_default()
);
} }
if let Some(mac) = host_mac { if let Some(mac) = host_mac {
tap.set_mac_addr(*mac).map_err(Error::TapSetMac)? tap.set_mac_addr(*mac).map_err(Error::TapSetMac)?

View File

@@ -17,14 +17,14 @@ vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", fea
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" } vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
serde = { version = "1.0.168", features = ["derive"] } serde = { version = "1.0.168", features = ["derive"] }
thiserror = "1.0.52" thiserror = "1.0.40"
versionize = "0.2.0" versionize = "0.1.10"
versionize_derive = "0.1.6" versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }

View File

@@ -58,8 +58,7 @@ pub trait PciDevice: BusDevice {
fn allocate_bars( fn allocate_bars(
&mut self, &mut self,
_allocator: &Arc<Mutex<SystemAllocator>>, _allocator: &Arc<Mutex<SystemAllocator>>,
_mmio32_allocator: &mut AddressAllocator, _mmio_allocator: &mut AddressAllocator,
_mmio64_allocator: &mut AddressAllocator,
_resources: Option<Vec<Resource>>, _resources: Option<Vec<Resource>>,
) -> Result<Vec<PciBarConfiguration>> { ) -> Result<Vec<PciBarConfiguration>> {
Ok(Vec::new()) Ok(Vec::new())
@@ -69,8 +68,7 @@ pub trait PciDevice: BusDevice {
fn free_bars( fn free_bars(
&mut self, &mut self,
_allocator: &mut SystemAllocator, _allocator: &mut SystemAllocator,
_mmio32_allocator: &mut AddressAllocator, _mmio_allocator: &mut AddressAllocator,
_mmio64_allocator: &mut AddressAllocator,
) -> Result<()> { ) -> Result<()> {
Ok(()) Ok(())
} }

View File

@@ -529,13 +529,10 @@ impl VfioCommon {
} }
} }
// The `allocator` argument is unused on `aarch64`
#[allow(unused_variables)]
pub(crate) fn allocate_bars( pub(crate) fn allocate_bars(
&mut self, &mut self,
allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>, resources: Option<Vec<Resource>>,
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> { ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
let mut bars = Vec::new(); let mut bars = Vec::new();
@@ -684,23 +681,26 @@ impl VfioCommon {
} }
PciBarRegionType::Memory32BitRegion => { PciBarRegionType::Memory32BitRegion => {
// BAR allocation must be naturally aligned // BAR allocation must be naturally aligned
mmio32_allocator allocator
.allocate(restored_bar_addr, region_size, Some(region_size)) .lock()
.unwrap()
.allocate_mmio_hole_addresses(
restored_bar_addr,
region_size,
Some(region_size),
)
.ok_or(PciDeviceError::IoAllocationFailed(region_size))? .ok_or(PciDeviceError::IoAllocationFailed(region_size))?
} }
PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory64BitRegion => {
// We need do some fixup to keep MMIO RW region and msix cap region page size // We need do some fixup to keep MMIO RW region and msix cap region page size
// aligned. // aligned.
region_size = self.fixup_msix_region(bar_id, region_size); region_size = self.fixup_msix_region(bar_id, region_size);
mmio64_allocator mmio_allocator
.allocate( .allocate(
restored_bar_addr, restored_bar_addr,
region_size, region_size,
Some(std::cmp::max( // SAFETY: FFI call. Trivially safe.
// SAFETY: FFI call. Trivially safe. Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
unsafe { sysconf(_SC_PAGESIZE) as GuestUsize },
region_size,
)),
) )
.ok_or(PciDeviceError::IoAllocationFailed(region_size))? .ok_or(PciDeviceError::IoAllocationFailed(region_size))?
} }
@@ -742,13 +742,10 @@ impl VfioCommon {
Ok(bars) Ok(bars)
} }
// The `allocator` argument is unused on `aarch64`
#[allow(unused_variables)]
pub(crate) fn free_bars( pub(crate) fn free_bars(
&mut self, &mut self,
allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> { ) -> Result<(), PciDeviceError> {
for region in self.mmio_regions.iter() { for region in self.mmio_regions.iter() {
match region.type_ { match region.type_ {
@@ -759,10 +756,10 @@ impl VfioCommon {
error!("I/O region is not supported"); error!("I/O region is not supported");
} }
PciBarRegionType::Memory32BitRegion => { PciBarRegionType::Memory32BitRegion => {
mmio32_allocator.free(region.start, region.length); allocator.free_mmio_hole_addresses(region.start, region.length);
} }
PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory64BitRegion => {
mmio64_allocator.free(region.start, region.length); mmio_allocator.free(region.start, region.length);
} }
} }
} }
@@ -1697,22 +1694,19 @@ impl PciDevice for VfioPciDevice {
fn allocate_bars( fn allocate_bars(
&mut self, &mut self,
allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>, resources: Option<Vec<Resource>>,
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> { ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
self.common self.common
.allocate_bars(allocator, mmio32_allocator, mmio64_allocator, resources) .allocate_bars(allocator, mmio_allocator, resources)
} }
fn free_bars( fn free_bars(
&mut self, &mut self,
allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> { ) -> Result<(), PciDeviceError> {
self.common self.common.free_bars(allocator, mmio_allocator)
.free_bars(allocator, mmio32_allocator, mmio64_allocator)
} }
fn write_config_register( fn write_config_register(

View File

@@ -397,22 +397,19 @@ impl PciDevice for VfioUserPciDevice {
fn allocate_bars( fn allocate_bars(
&mut self, &mut self,
allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>, resources: Option<Vec<Resource>>,
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> { ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
self.common self.common
.allocate_bars(allocator, mmio32_allocator, mmio64_allocator, resources) .allocate_bars(allocator, mmio_allocator, resources)
} }
fn free_bars( fn free_bars(
&mut self, &mut self,
allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
mmio32_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
mmio64_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> { ) -> Result<(), PciDeviceError> {
self.common self.common.free_bars(allocator, mmio_allocator)
.free_bars(allocator, mmio32_allocator, mmio64_allocator)
} }
fn as_any(&mut self) -> &mut dyn Any { fn as_any(&mut self) -> &mut dyn Any {

View File

@@ -6,7 +6,7 @@ edition = "2021"
build = "../build.rs" build = "../build.rs"
[dependencies] [dependencies]
clap = { version = "4.4.7", features = ["wrap_help"] } argh = "0.1.9"
dirs = "5.0.0" dirs = "5.0.0"
serde = { version = "1.0.168", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"

View File

@@ -8,11 +8,11 @@ extern crate test_infra;
mod performance_tests; mod performance_tests;
use clap::{Arg, ArgAction, Command as ClapCommand}; use argh::FromArgs;
use performance_tests::*; use performance_tests::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
env, fmt, fmt,
process::Command, process::Command,
sync::{mpsc::channel, Arc}, sync::{mpsc::channel, Arc},
thread, thread,
@@ -639,45 +639,41 @@ fn date() -> String {
String::from_utf8_lossy(&output.stdout).trim().to_string() String::from_utf8_lossy(&output.stdout).trim().to_string()
} }
#[derive(FromArgs)]
/// Generate the performance metrics data for Cloud Hypervisor
struct Options {
#[argh(switch, long = "list-tests")]
/// print the list of available metrics tests
list_tests: bool,
#[argh(option, long = "test-filter")]
/// filter metrics tests to run based on provided keywords
keywords: Vec<String>,
#[argh(option, long = "report-file")]
/// report file. Stderr is used if not specified
report_file: Option<String>,
#[argh(option, long = "iterations")]
/// override number of test iterations
iterations: Option<u32>,
#[argh(option, long = "timeout")]
/// override test timeout, Ex. --timeout 5
timeout: Option<u32>,
#[argh(switch, short = 'V', long = "version")]
/// print version information
version: bool,
}
fn main() { fn main() {
let cmd_arguments = ClapCommand::new("performance-metrics") let opts: Options = argh::from_env();
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS")) if opts.version {
.about("Generate the performance metrics data for Cloud Hypervisor") println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
.arg( return;
Arg::new("test-filter") }
.long("test-filter")
.help("Filter metrics tests to run based on provided keywords")
.num_args(1)
.required(false),
)
.arg(
Arg::new("list-tests")
.long("list-tests")
.help("Print the list of available metrics tests")
.num_args(0)
.action(ArgAction::SetTrue)
.required(false),
)
.arg(
Arg::new("report-file")
.long("report-file")
.help("Report file. Standard error is used if not specified")
.num_args(1),
)
.arg(
Arg::new("iterations")
.long("iterations")
.help("Override number of test iterations")
.num_args(1),
)
.arg(
Arg::new("timeout")
.long("timeout")
.help("Override test timeout, Ex. --timeout 5")
.num_args(1),
)
.get_matches();
// It seems that the tool (ethr) used for testing the virtio-net latency // It seems that the tool (ethr) used for testing the virtio-net latency
// is not stable on AArch64, and therefore the latency test is currently // is not stable on AArch64, and therefore the latency test is currently
@@ -687,7 +683,7 @@ fn main() {
.filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us")) .filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us"))
.collect(); .collect();
if cmd_arguments.get_flag("list-tests") { if opts.list_tests {
for test in test_list.iter() { for test in test_list.iter() {
println!("\"{}\" ({})", test.name, test.control); println!("\"{}\" ({})", test.name, test.control);
} }
@@ -695,10 +691,7 @@ fn main() {
return; return;
} }
let test_filter = match cmd_arguments.get_many::<String>("test-filter") { let test_filter = opts.keywords.iter().collect::<Vec<&String>>();
Some(s) => s.collect(),
None => Vec::new(),
};
// Run performance tests sequentially and report results (in both readable/json format) // Run performance tests sequentially and report results (in both readable/json format)
let mut metrics_report: MetricsReport = Default::default(); let mut metrics_report: MetricsReport = Default::default();
@@ -706,16 +699,8 @@ fn main() {
init_tests(); init_tests();
let overrides = Arc::new(PerformanceTestOverrides { let overrides = Arc::new(PerformanceTestOverrides {
test_iterations: cmd_arguments test_iterations: opts.iterations,
.get_one::<String>("iterations") test_timeout: opts.timeout,
.map(|s| s.parse())
.transpose()
.unwrap_or_default(),
test_timeout: cmd_arguments
.get_one::<String>("timeout")
.map(|s| s.parse())
.transpose()
.unwrap_or_default(),
}); });
for test in test_list.iter() { for test in test_list.iter() {
@@ -734,19 +719,18 @@ fn main() {
cleanup_tests(); cleanup_tests();
let mut report_file: Box<dyn std::io::Write + Send> = let mut report_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = opts.report_file {
if let Some(file) = cmd_arguments.get_one::<String>("report-file") { Box::new(
Box::new( std::fs::File::create(std::path::Path::new(file))
std::fs::File::create(std::path::Path::new(file)) .map_err(|e| {
.map_err(|e| { eprintln!("Error opening report file: {file}: {e}");
eprintln!("Error opening report file: {file}: {e}"); std::process::exit(1);
std::process::exit(1); })
}) .unwrap(),
.unwrap(), )
) } else {
} else { Box::new(std::io::stdout())
Box::new(std::io::stdout()) };
};
report_file report_file
.write_all( .write_all(

View File

@@ -19,7 +19,6 @@ pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-0-update-tool.raw"; pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-0-update-tool.raw";
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
enum Error { enum Error {
BootTimeParse, BootTimeParse,
@@ -359,11 +358,13 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
guest.disk_config.disk(DiskType::OperatingSystem).unwrap() guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
) )
.as_str(), .as_str(),
"--disk",
format!( format!(
"path={}", "path={}",
guest.disk_config.disk(DiskType::CloudInit).unwrap() guest.disk_config.disk(DiskType::CloudInit).unwrap()
) )
.as_str(), .as_str(),
"--disk",
format!("path={BLK_IO_TEST_IMG}").as_str(), format!("path={BLK_IO_TEST_IMG}").as_str(),
]) ])
.default_net() .default_net()

View File

@@ -5,6 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
thiserror = "1.0.40" vmm-sys-util = "0.11.0"
vmm-sys-util = "0.12.1"

View File

@@ -1,61 +1,43 @@
- [v37.1](#v371) - [v35.1](#v351)
- [v37.0](#v370)
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
- [Improved VFIO Device Passthrough with Multiple PCI Segments](#improved-vfio-device-passthrough-with-multiple-pci-segments)
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v36.0](#v360)
- [Command Line Changes](#command-line-changes)
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
- [NUMA Support for PCI segments](#numa-support-for-pci-segments)
- [CPU Topology Support on AMD Platforms](#cpu-topology-support-on-amd-platforms)
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
- [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v35.0](#v350) - [v35.0](#v350)
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63) - [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block) - [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state) - [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
- [Notable Bug Fixes](#notable-bug-fixes-2) - [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors-2) - [Contributors](#contributors)
- [v34.0](#v340) - [v34.0](#v340)
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support) - [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump) - [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files) - [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump) - [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
- [Notable Bug Fixes](#notable-bug-fixes-3) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-3) - [Contributors](#contributors-1)
- [v33.0](#v330) - [v33.0](#v330)
- [D-Bus based API](#d-bus-based-api) - [D-Bus based API](#d-bus-based-api)
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64) - [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-4) - [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-4) - [Contributors](#contributors-2)
- [v32.0](#v320) - [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit) - [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes) - [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes-5) - [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-5) - [Contributors](#contributors-3)
- [v31.1](#v311) - [v31.1](#v311)
- [v31.0](#v310) - [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables) - [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62) - [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler) - [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile) - [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements-1) - [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-6) - [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-6) - [Contributors](#contributors-4)
- [v30.0](#v300) - [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size) - [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support) - [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support) - [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-2) - [Documentation Improvements](#documentation-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-7) - [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-7) - [Contributors](#contributors-5)
- [v28.2](#v282) - [v28.2](#v282)
- [v29.0](#v290) - [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm) - [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -65,20 +47,20 @@
- [`AArch64` Documentation Integration](#aarch64-documentation-integration) - [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement) - [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control) - [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes-8) - [Notable Bug Fixes](#notable-bug-fixes-6)
- [Removals](#removals) - [Removals](#removals)
- [Deprecations](#deprecations) - [Deprecations](#deprecations)
- [Contributors](#contributors-8) - [Contributors](#contributors-6)
- [v28.1](#v281) - [v28.1](#v281)
- [v28.0](#v280) - [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder) - [Community Engagement (Reminder)](#community-engagement-reminder)
- [Long Term Support (LTS) Release](#long-term-support-lts-release-1) - [Long Term Support (LTS) Release](#long-term-support-lts-release)
- [Virtualised TPM Support](#virtualised-tpm-support) - [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support) - [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved) - [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes-9) - [Notable Bug Fixes](#notable-bug-fixes-7)
- [Removals](#removals-1) - [Removals](#removals-1)
- [Contributors](#contributors-9) - [Contributors](#contributors-7)
- [v27.0](#v270) - [v27.0](#v270)
- [Community Engagement](#community-engagement) - [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages) - [Prebuilt Packages](#prebuilt-packages)
@@ -87,41 +69,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags) - [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading) - [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64) - [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-10) - [Notable Bug Fixes](#notable-bug-fixes-8)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-10) - [Contributors](#contributors-8)
- [v26.0](#v260) - [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform) - [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support) - [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
- [Notable Bug Fixes](#notable-bug-fixes-11) - [Notable Bug Fixes](#notable-bug-fixes-9)
- [Deprecations](#deprecations-2) - [Deprecations](#deprecations-2)
- [Removals](#removals-2) - [Removals](#removals-2)
- [Contributors](#contributors-11) - [Contributors](#contributors-9)
- [v25.0](#v250) - [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1) - [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support) - [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-12) - [Notable Bug Fixes](#notable-bug-fixes-10)
- [Removals](#removals-3) - [Removals](#removals-3)
- [Contributors](#contributors-12) - [Contributors](#contributors-10)
- [v24.0](#v240) - [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu) - [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness) - [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support) - [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number) - [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-13) - [Notable Bug Fixes](#notable-bug-fixes-11)
- [Notable Improvements](#notable-improvements) - [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3) - [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website) - [New on the Website](#new-on-the-website)
- [Contributors](#contributors-13) - [Contributors](#contributors-11)
- [v23.1](#v231) - [v23.1](#v231)
- [v23.0](#v230) - [v23.0](#v230)
- [vDPA Support](#vdpa-support) - [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list) - [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements) - [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support) - [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-14) - [Notable Bug Fixes](#notable-bug-fixes-12)
- [Deprecations](#deprecations-4) - [Deprecations](#deprecations-4)
- [Contributors](#contributors-14) - [Contributors](#contributors-12)
- [v22.1](#v221) - [v22.1](#v221)
- [v22.0](#v220) - [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support) - [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -132,13 +114,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64) - [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license) - [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd) - [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-15) - [Notable Bug Fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-15) - [Contributors](#contributors-13)
- [v21.0](#v210) - [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade) - [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515) - [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-16) - [Notable Bug fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-16) - [Contributors](#contributors-14)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -147,8 +129,8 @@
- [Improved VFIO support](#improved-vfio-support) - [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code) - [Safer code](#safer-code)
- [Extended documentation](#extended-documentation) - [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-17) - [Notable bug fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-17) - [Contributors](#contributors-15)
- [v19.0](#v190) - [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console) - [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations) - [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -156,8 +138,8 @@
- [Live migration enhancements](#live-migration-enhancements) - [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user) - [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu) - [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-18) - [Notable bug fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-18) - [Contributors](#contributors-16)
- [v18.0](#v180) - [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support) - [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices) - [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -167,23 +149,23 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor) - [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support) - [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64) - [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-19) - [Notable bug fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-19) - [Contributors](#contributors-17)
- [v17.0](#v170) - [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi) - [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend) - [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices) - [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support) - [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices) - [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-20) - [Notable bug fixes](#notable-bug-fixes-18)
- [Contributors](#contributors-20) - [Contributors](#contributors-18)
- [v16.0](#v160) - [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support) - [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support) - [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support) - [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-21) - [Notable bug fixes](#notable-bug-fixes-19)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-21) - [Contributors](#contributors-19)
- [v15.0](#v150) - [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees) - [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting) - [Network device rate limiting](#network-device-rate-limiting)
@@ -191,7 +173,7 @@
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter) - [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes) - [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-5) - [Deprecations](#deprecations-5)
- [Contributors](#contributors-22) - [Contributors](#contributors-20)
- [v0.14.1](#v0141) - [v0.14.1](#v0141)
- [v0.14.0](#v0140) - [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring) - [Structured event monitoring](#structured-event-monitoring)
@@ -201,7 +183,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console) - [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting) - [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-6) - [Deprecations](#deprecations-6)
- [Contributors](#contributors-23) - [Contributors](#contributors-21)
- [v0.13.0](#v0130) - [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support) - [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support) - [Improved huge page support](#improved-huge-page-support)
@@ -209,13 +191,13 @@
- [VHD disk image support](#vhd-disk-image-support) - [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading) - [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button) - [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-24) - [Contributors](#contributors-22)
- [v0.12.0](#v0120) - [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements) - [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning) - [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend) - [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api) - [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-25) - [Contributors](#contributors-23)
- [v0.11.0](#v0110) - [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block) - [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support) - [Windows Guest Support](#windows-guest-support)
@@ -227,15 +209,15 @@
- [Default Log Level Changed](#default-log-level-changed) - [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added) - [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support) - [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-22) - [Notable Bug Fixes](#notable-bug-fixes-20)
- [Contributors](#contributors-26) - [Contributors](#contributors-24)
- [v0.10.0](#v0100) - [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors) - [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones) - [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control) - [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-23) - [Notable Bug Fixes](#notable-bug-fixes-21)
- [Contributors](#contributors-27) - [Contributors](#contributors-25)
- [v0.9.0](#v090) - [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support) - [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics) - [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -248,17 +230,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support) - [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support) - [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-24) - [Notable Bug Fixes](#notable-bug-fixes-22)
- [Contributors](#contributors-28) - [Contributors](#contributors-26)
- [v0.8.0](#v080) - [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support) - [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support) - [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests) - [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices) - [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements) - [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-25) - [Notable Bug Fixes](#notable-bug-fixes-23)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-29) - [Contributors](#contributors-27)
- [v0.7.0](#v070) - [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug) - [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support) - [Alternative `libc` Support](#alternative-libc-support)
@@ -268,14 +250,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing) - [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support) - [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1) - [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-30) - [Contributors](#contributors-28)
- [v0.6.0](#v060) - [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug) - [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements) - [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading) - [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface) - [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot) - [PVH Boot](#pvh-boot)
- [Contributors](#contributors-31) - [Contributors](#contributors-29)
- [v0.5.1](#v051) - [v0.5.1](#v051)
- [v0.5.0](#v050) - [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing) - [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -283,7 +265,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework) - [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools) - [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration) - [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-32) - [Contributors](#contributors-30)
- [v0.4.0](#v040) - [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition) - [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation) - [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -292,7 +274,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default) - [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming) - [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization) - [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-33) - [Contributors](#contributors-31)
- [v0.3.0](#v030) - [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading) - [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend) - [Network device backend](#network-device-backend)
@@ -319,155 +301,16 @@
- [Unit testing](#unit-testing) - [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization) - [Integration tests parallelization](#integration-tests-parallelization)
# v37.1 # v35.1
This is a bug fix release. The following issues have been addressed: This is a bug fix release. The following issues have been addressed:
* Fix several security advisories from dependencies (#6134, #6141) * Fix a deadlock when TDX is enabled (#5845)
* Enable HTT flag to avoid crashing cpu topology enumeration software * Correct default value for vCPU topology on AArch64 (#5893)
such as hwloc in the guest (#6146)
* Enable nested virtualization on AMD if supported (#6106)
* Handle non-power-of-two CPU topology properly (#6062)
* Various bug fixes around virtio-vsock(#6080, #6091, #6095)
* Align VFIO devices PCI BARs naturally (#6196)
# v37.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v37.0. The following user visible changes have been made:
### Long Term Support (LTS) Release
This release is a LTS release. Point releases for bug fixes will be made
for the next 18 months; live migration and live upgrade will be
supported between the point releases of the LTS.
### Multiple PCI segments Support for 32-bit VFIO devices
Now VFIO devices with 32-bit memory BARs can be attached to non-zero PCI
segments on the guest, allowing users to have more 32-bit devices and
assign such devices to appropriate NUMA nodes for better performance.
### Configurable Named TAP Devices
Named TAP devices now accepts IP configuration from users, such as IP
and MAC address, as long as the named TAP device is created by Cloud
Hypervisor (e.g. not existing TAP devices).
### TTY Output from Both Serial Device and Virtio Console
Now legacy serial device and virtio console can be set as TTY mode as
the same time. This allows users to capture early boot logs with the
legacy serial device without losing performance benefits of using
virtio-console, when appropriate kernel configuration is used (such as
using kernel command-line `console=hvc0 earlyprintk=ttyS0` on x86).
### Faster VM Restoration from Snapshots
The speed of VM restoration from snapshots is improved with a better
implementation of deserializing JSON files.
### Notable Bug Fixes
* Fix aio backend behavior for block devices when writeback cache
disabled (#5930)
* Fix PvPanic device PCI BAR alignment (#5956) * Fix PvPanic device PCI BAR alignment (#5956)
* Bug fix to OpenAPI specification file (#5967) * Bug fix to OpenAPI specification file (#5967)
* Error out early for live migration when TDX is enabled (#6025) * Error out early for live migration when TDX is enabled (#6025)
### Contributors
Many thanks to everyone who has contributed to our release:
* Bo Chen <chen.bo@intel.com>
* Jinank Jain <jinankjain@microsoft.com>
* Markus Sütter <markus.suetter@secunet.com>
* Michael Zhao <michael.zhao@arm.com>
* Muminul Islam <muislam@microsoft.com>
* Rob Bradford <rbradford@rivosinc.com>
* Rui Chang <rui.chang@arm.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Thomas Barrett <tbarrett@crusoeenergy.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <foxywang@tencent.com>
* Yong He <alexyonghe@tencent.com>
# v36.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v36.0. The following user visible changes have been made:
### Command Line Changes
We switched back to use the `clap` crate to create our command line,
since the `argh` crate is barely maintained. There were several syntax
changes:
* All `--option value` commands now are `--option=value`.
* The `--disk DISK1 --disk DISK2` command now is `--disk DISK1 DISK2`.
* The `-v -v -v`command now is `-vvv`.
Note: the released binary size increased around 0.3M due to this change.
### Enabled Features Reported via API Endpoint and CLI
Now the enabled (Cargo) features of the running Cloud Hypervisor
instance can be queried via API endpoint (`/vmm.ping`) and CLI
(`--version -v`).
### NUMA Support for PCI segments
The `--numa` command is augmented with a new option `pci_segment=`, so
that users can define the relationship between PCI segments and NUMA
nodes. Examples can be found from the [memory documentation](docs/memory.md)
### CPU Topology Support on AMD Platforms
Now the CPU topology on x86_64 platforms supports multiple vendors.
### Unix Socket Backend for Serial Port
The `--serial` command is augmented with a new option `socket=`, allowing
users to access the serial port using a Unix socket.
### AIO Backend for Block Devices
An AIO backend is added for `virtio-block` devices to improve block
device performance when the `io_uring` feature is not supported by the
host Operating System.
### Documentation Improvements
* New [documentation](docs/coverage.md) for collecting coverage data
* Various typo fixes
### Notable Bug Fixes
* Fix a deadlock when TDX is enabled (#5845)
* Only advertise AMX feature bits to guest when the AMX cpu feature is
enabled (#5834)
* Correct default value for vCPU topology on AArch64 (#5893)
### Contributors
Many thanks to everyone who has contributed to our release:
* Anatol Belski <anbelski@linux.microsoft.com>
* Bo Chen <chen.bo@intel.com>
* Dario Nieuwenhuis <dirbaio@dirbaio.net>
* Jianyong Wu <jianyong.wu@arm.com>
* Jinank Jain <jinankjain@microsoft.com>
* Muminul Islam <muislam@microsoft.com>
* Praveen K Paladugu <prapal@linux.microsoft.com>
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
* Rob Bradford <rbradford@rivosinc.com>
* Thomas Barrett <tbarrett@crusoeenergy.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <foxywang@tencent.com>
* dom.song <dom.song@amperecomputing.com>
# v35.0 # v35.0
This release has been tracked in our [roadmap This release has been tracked in our [roadmap

View File

@@ -6,7 +6,7 @@
FROM ubuntu:22.04 as dev FROM ubuntu:22.04 as dev
ARG TARGETARCH ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.70.0" ARG RUST_TOOLCHAIN="1.67.1"
ARG CLH_SRC_DIR="/cloud-hypervisor" ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build" ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry" ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"

View File

@@ -639,7 +639,7 @@ CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y CONFIG_KVM=y
# CONFIG_KVM_WERROR is not set # CONFIG_KVM_WERROR is not set
CONFIG_KVM_INTEL=y CONFIG_KVM_INTEL=y
CONFIG_KVM_AMD=y # CONFIG_KVM_AMD is not set
CONFIG_KVM_SMM=y CONFIG_KVM_SMM=y
# CONFIG_KVM_XEN is not set # CONFIG_KVM_XEN is not set
CONFIG_AS_AVX512=y CONFIG_AS_AVX512=y

View File

@@ -434,7 +434,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $? dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -456,7 +455,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -478,7 +476,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -500,7 +497,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_integration_tests_windows_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_integration_tests_windows_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -522,7 +518,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -544,7 +539,6 @@ cmd_tests() {
--env BUILD_TARGET="$target" \ --env BUILD_TARGET="$target" \
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_integration_tests_rate_limiter.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_integration_tests_rate_limiter.sh "$@" || fix_dir_perms $? || exit $?
fi fi
@@ -567,7 +561,6 @@ cmd_tests() {
--env RUSTFLAGS="$rustflags" \ --env RUSTFLAGS="$rustflags" \
--env TARGET_CC="$target_cc" \ --env TARGET_CC="$target_cc" \
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \ --env RUST_BACKTRACE="${RUST_BACKTRACE}" \
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
fi fi

View File

@@ -1,91 +0,0 @@
from gitlint.rules import LineRule, RuleViolation, CommitMessageTitle
import re
class TitleStartsWithComponent(LineRule):
"""A rule to enforce valid commit message title
Valid title format:
component1[, component2, componentN]: submodule: summary
Title should have at least one component
Components are separated by comma+space: ", "
Components are validated to be in valid_components
Components list is ended by a colon
Submodules are not validated
"""
# A rule MUST have a human friendly name
name = "title-has-valid-component"
# A rule MUST have a *unique* id.
# We recommend starting with UL (for User-defined Line-rule)
id = "UL1"
# A line-rule MUST have a target (not required for CommitRules).
target = CommitMessageTitle
def validate(self, line, _commit):
valid_components = (
'api_client',
'arch',
'block',
'build',
'ch-remote',
'ci',
'devices',
'docs',
'event_monitor',
'fuzz',
'github',
'gitignore',
'gitlint',
'hypervisor',
'main',
'misc',
'net_gen',
'net_util',
'option_parser',
'pci',
'performance-metrics',
'rate_limiter',
'README',
'resources',
'scripts',
'serial_buffer',
'test_data',
'test_infra',
'tests',
'tpm',
'tracer',
'vhost_user_block',
'vhost_user_net',
'virtio-devices',
'vm-allocator',
'vm-device',
'vmm',
'vm-migration',
'vm-virtio')
ptrn_title = re.compile(r'^(.+?):\s(.+)$')
match = ptrn_title.match(line)
if not match:
self.log.debug("Invalid commit title {}", line)
return [RuleViolation(self.id, "Commit title does not comply with "
"rule: 'component: change summary'")]
components = match.group(1)
summary = match.group(2)
self.log.debug(f"\nComponents: {components}\nSummary: {summary}")
ptrn_components = re.compile(r',\s')
components_list = re.split(ptrn_components, components)
self.log.debug("components list: %s" % components_list)
for component in components_list:
if component not in valid_components:
return [RuleViolation(self.id,
f"Invalid component: {component}, "
"\nValid components are: {}".format(
" ".join(valid_components)))]

View File

@@ -42,8 +42,7 @@ build_virtiofsd() {
if [ ! -f "$VIRTIOFSD_DIR/.built" ]; then if [ ! -f "$VIRTIOFSD_DIR/.built" ]; then
pushd $VIRTIOFSD_DIR pushd $VIRTIOFSD_DIR
rm -rf target/ time cargo build --release
time RUSTFLAGS="" TARGET_CC="" cargo build --release
cp target/release/virtiofsd "$WORKLOADS_DIR/" || exit 1 cp target/release/virtiofsd "$WORKLOADS_DIR/" || exit 1
touch .built touch .built
popd popd
@@ -53,8 +52,35 @@ build_virtiofsd() {
update_workloads() { update_workloads() {
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
BIONIC_OS_IMAGE_DOWNLOAD_NAME="bionic-server-cloudimg-arm64.img"
BIONIC_OS_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
BIONIC_OS_DOWNLOAD_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
if [ ! -f "$BIONIC_OS_DOWNLOAD_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $BIONIC_OS_IMAGE_DOWNLOAD_URL || exit 1
popd
fi
BIONIC_OS_RAW_IMAGE_NAME="bionic-server-cloudimg-arm64.raw"
BIONIC_OS_RAW_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_RAW_IMAGE_NAME"
if [ ! -f "$BIONIC_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img convert -p -f qcow2 -O raw $BIONIC_OS_IMAGE_DOWNLOAD_NAME $BIONIC_OS_RAW_IMAGE_NAME || exit 1
popd
fi
# Convert the raw image to qcow2 image to remove compressed blocks from the disk. Therefore letting the
# qcow2 format image can be directly used in the integration test.
BIONIC_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="bionic-server-cloudimg-arm64.qcow2"
BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
if [ ! -f "$BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img convert -p -f raw -O qcow2 $BIONIC_OS_RAW_IMAGE_NAME $BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE || exit 1
popd
fi
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw" FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw"
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://ch-images.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME" FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME"
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME" FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -63,7 +89,7 @@ update_workloads() {
fi fi
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2" FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://ch-images.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME" FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME" FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -80,7 +106,7 @@ update_workloads() {
fi fi
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.raw" JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.raw"
JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL="https://ch-images.azureedge.net/$JAMMY_OS_RAW_IMAGE_NAME" JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_RAW_IMAGE_NAME"
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME" JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -89,7 +115,7 @@ update_workloads() {
fi fi
JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.qcow2" JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.qcow2"
JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://ch-images.azureedge.net/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME" JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME" JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
if [ ! -f "$JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then if [ ! -f "$JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -132,7 +158,7 @@ update_workloads() {
popd popd
# Download Cloud Hypervisor binary from its last stable release # Download Cloud Hypervisor binary from its last stable release
LAST_RELEASE_VERSION="v36.0" LAST_RELEASE_VERSION="v34.0"
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64" CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64" CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -19,7 +19,7 @@ fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2" FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
FOCAL_OS_IMAGE_URL="https://ch-images.azureedge.net/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then if [ ! -f "$FOCAL_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -44,7 +44,7 @@ fi
popd popd
# Download Cloud Hypervisor binary from its last stable release # Download Cloud Hypervisor binary from its last stable release
LAST_RELEASE_VERSION="v36.0" LAST_RELEASE_VERSION="v34.0"
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static" CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static"
CH_RELEASE_NAME="cloud-hypervisor-static" CH_RELEASE_NAME="cloud-hypervisor-static"
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -19,7 +19,7 @@ fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2" FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
FOCAL_OS_IMAGE_URL="https://ch-images.azureedge.net/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then if [ ! -f "$FOCAL_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -14,10 +14,15 @@ fi
WORKLOADS_DIR="$HOME/workloads" WORKLOADS_DIR="$HOME/workloads"
mkdir -p "$WORKLOADS_DIR" mkdir -p "$WORKLOADS_DIR"
download_hypervisor_fw FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
FW="$WORKLOADS_DIR/hypervisor-fw"
pushd $WORKLOADS_DIR
rm -f $FW
time wget --quiet $FW_URL || exit 1
popd
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2" JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
JAMMY_OS_IMAGE_URL="https://ch-images.azureedge.net/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_IMAGE" ]; then if [ ! -f "$JAMMY_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -1,20 +1,72 @@
#!/bin/bash #!/bin/bash
set -x set -x
# This set of vfio tests require to be ran on a specific machine with
# specific hardware (e.g. the "vfio" bera-metal worker equipped with a
# Nvidia Tesla T4 card). So the provisioning of the running machine is
# out of the scope of this script, including the custom guest image with
# Nvidia drivers installed, and properly configured Nvidia Tesla T4 card.
source $HOME/.cargo/env source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh source $(dirname "$0")/test-util.sh
process_common_args "$@" process_common_args "$@"
WORKLOADS_DIR="$HOME/workloads" WORKLOADS_DIR="$HOME/workloads"
mkdir -p "$WORKLOADS_DIR"
download_hypervisor_fw cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
FW="$WORKLOADS_DIR/hypervisor-fw"
if [ ! -f "$FW" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $FW_URL || exit 1
popd
fi
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
popd
fi
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
popd
fi
pushd $WORKLOADS_DIR
sha1sum sha1sums-x86_64 --check --ignore-missing
if [ $? -ne 0 ]; then
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
exit 1
fi
popd
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
build_custom_linux
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
MNT_DIR="mount_image"
rm -rf $BLK_IMAGE
pushd $WORKLOADS_DIR
fallocate -l 16M $BLK_IMAGE
mkfs.ext4 -j $BLK_IMAGE
mkdir $MNT_DIR
sudo mount -t ext4 $BLK_IMAGE $MNT_DIR
sudo bash -c "echo bar > $MNT_DIR/foo" || exit 1
sudo umount $BLK_IMAGE
rm -r $MNT_DIR
popd
VFIO_DIR="$WORKLOADS_DIR/vfio"
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
mkdir -p $VFIO_DIR
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
cp $FW $VFIO_DIR
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
CFLAGS="" CFLAGS=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
@@ -23,8 +75,23 @@ fi
cargo build --features mshv --all --release --target $BUILD_TARGET cargo build --features mshv --all --release --target $BUILD_TARGET
# We always copy a fresh version of our binary for our L2 guest.
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
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]} time cargo test "vfio::test_vfio" -- ${test_binary_args[*]}
RES=$? RES=$?
if [ $RES -eq 0 ]; then
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
RES=$?
fi
exit $RES exit $RES

View File

@@ -18,7 +18,13 @@ fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
download_hypervisor_fw FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
FW="$WORKLOADS_DIR/hypervisor-fw"
if [ ! -f "$FW" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $FW_URL || exit 1
popd
fi
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]') OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd" OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
@@ -29,7 +35,7 @@ if [ ! -f "$OVMF_FW" ]; then
fi fi
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2" FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
FOCAL_OS_IMAGE_URL="https://ch-images.azureedge.net/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then if [ ! -f "$FOCAL_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR
@@ -54,7 +60,7 @@ if [ ! -f "$FOCAL_OS_QCOW_BACKING_FILE_IMAGE" ]; then
fi fi
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2" JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
JAMMY_OS_IMAGE_URL="https://ch-images.azureedge.net/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_IMAGE" ]; then if [ ! -f "$JAMMY_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -34,7 +34,7 @@ else
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2" FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
fi fi
FOCAL_OS_IMAGE_URL="https://ch-images.azureedge.net/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then if [ ! -f "$FOCAL_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR pushd $WORKLOADS_DIR

View File

@@ -1,3 +1,6 @@
6fee67adbfed8db7a225be23ee9d90b5bd7f19e6 bionic-server-cloudimg-arm64.img
786fe1c33588334e92b35c65e414da068df180bc bionic-server-cloudimg-arm64.raw
6e66f9f4b01adc72c884c1c1111e60afadc9c871 bionic-server-cloudimg-arm64.qcow2
e4addb6e212a298144f9eb0eb6e36019d013f0e7 alpine-minirootfs-aarch64.tar.gz e4addb6e212a298144f9eb0eb6e36019d013f0e7 alpine-minirootfs-aarch64.tar.gz
25b4f9ac308898d63b73d7db0e0e2d4768853723 focal-server-cloudimg-arm64-custom-20210929-0.qcow2 25b4f9ac308898d63b73d7db0e0e2d4768853723 focal-server-cloudimg-arm64-custom-20210929-0.qcow2
9953b31bb1923cdd8d91b1b7cc9ad3a9be1e0a59 focal-server-cloudimg-arm64-custom-20210929-0.raw 9953b31bb1923cdd8d91b1b7cc9ad3a9be1e0a59 focal-server-cloudimg-arm64-custom-20210929-0.raw

View File

@@ -107,20 +107,3 @@ process_common_args() {
test_binary_args=($@) test_binary_args=($@)
} }
download_hypervisor_fw() {
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
echo "Using authenticated download from GitHub"
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest \
--header "Authorization: Token $AUTH_DOWNLOAD_TOKEN" \
--header "X-GitHub-Api-Version: 2022-11-28" | grep "browser_download_url" | grep -o 'https://.*[^ "]')
else
echo "Using anonymous download from GitHub"
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
fi
FW="$WORKLOADS_DIR/hypervisor-fw"
pushd $WORKLOADS_DIR
rm -f $FW
time wget --quiet $FW_URL || exit 1
popd
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
#[macro_use] #[macro_use]
extern crate event_monitor; extern crate event_monitor;
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command}; use argh::FromArgs;
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use log::{warn, LevelFilter}; use log::{warn, LevelFilter};
use option_parser::OptionParser; use option_parser::OptionParser;
@@ -128,10 +128,6 @@ impl log::Log for Logger {
fn flush(&self) {} fn flush(&self) {}
} }
fn prepare_default_values() -> (String, String, String) {
(default_vcpus(), default_memory(), default_rng())
}
fn default_vcpus() -> String { fn default_vcpus() -> String {
format!( format!(
"boot={},max_phys_bits={}", "boot={},max_phys_bits={}",
@@ -148,330 +144,280 @@ fn default_rng() -> String {
format!("src={}", config::DEFAULT_RNG_SOURCE) format!("src={}", config::DEFAULT_RNG_SOURCE)
} }
fn create_app(default_vcpus: String, default_memory: String, default_rng: String) -> Command { #[derive(FromArgs)]
#[allow(clippy::let_and_return)] /// Launch a cloud-hypervisor VMM.
let app = Command::new("cloud-hypervisor") pub struct TopLevel {
// 'BUILD_VERSION' is set by the build script 'build.rs' at #[argh(option, long = "cpus", default = "default_vcpus()")]
// compile time /// boot=<boot_vcpus>, max=<max_vcpus>, topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>, kvm_hyperv=on|off, max_phys_bits=<maximum_number_of_physical_bits>, affinity=<list_of_vcpus_with_their_associated_cpuset>, features=<list_of_features_to_enable>
.author(env!("CARGO_PKG_AUTHORS")) cpus: String,
.about("Launch a cloud-hypervisor VMM.")
.group(ArgGroup::new("vm-config").multiple(true))
.group(ArgGroup::new("vmm-config").multiple(true))
.group(ArgGroup::new("logging").multiple(true))
.arg(
Arg::new("cpus")
.long("cpus")
.help(
"boot=<boot_vcpus>,max=<max_vcpus>,\
topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,\
kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,\
affinity=<list_of_vcpus_with_their_associated_cpuset>,\
features=<list_of_features_to_enable>",
)
.default_value(default_vcpus)
.group("vm-config"),
)
.arg(
Arg::new("platform")
.long("platform")
.help("num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>")
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("memory")
.long("memory")
.help(
"Memory parameters \
\"size=<guest_memory_size>,mergeable=on|off,shared=on|off,\
hugepages=on|off,hugepage_size=<hugepage_size>,\
hotplug_method=acpi|virtio-mem,\
hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off,thp=on|off\"",
)
.default_value(default_memory)
.group("vm-config"),
)
.arg(
Arg::new("memory-zone")
.long("memory-zone")
.help(
"User defined memory zone parameters \
\"size=<guest_memory_region_size>,file=<backing_file>,\
shared=on|off,\
hugepages=on|off,hugepage_size=<hugepage_size>,\
host_numa_node=<node_id>,\
id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
hotplugged_size=<hotplugged_memory_size>,\
prefault=on|off\"",
)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("firmware")
.long("firmware")
.help("Path to firmware that is loaded in an architectural specific way")
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("kernel")
.long("kernel")
.help(
"Path to kernel to load. This may be a kernel or firmware that supports a PVH \
entry point (e.g. vmlinux) or architecture equivalent",
)
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("initramfs")
.long("initramfs")
.help("Path to initramfs image")
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("cmdline")
.long("cmdline")
.help("Kernel command line")
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("disk")
.long("disk")
.help(config::DiskConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("net")
.long("net")
.help(config::NetConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("rng")
.long("rng")
.help(
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
)
.default_value(default_rng)
.group("vm-config"),
)
.arg(
Arg::new("balloon")
.long("balloon")
.help(config::BalloonConfig::SYNTAX)
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("fs")
.long("fs")
.help(config::FsConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("pmem")
.long("pmem")
.help(config::PmemConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("serial")
.long("serial")
.help("Control serial port: off|null|pty|tty|file=</path/to/a/file>|socket=</path/to/a/file>")
.default_value("null")
.group("vm-config"),
)
.arg(
Arg::new("console")
.long("console")
.help(
"Control (virtio) console: \"off|null|pty|tty|file=</path/to/a/file>,iommu=on|off\"",
)
.default_value("tty")
.group("vm-config"),
)
.arg(
Arg::new("device")
.long("device")
.help(config::DeviceConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("user-device")
.long("user-device")
.help(config::UserDeviceConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("vdpa")
.long("vdpa")
.help(config::VdpaConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("vsock")
.long("vsock")
.help(config::VsockConfig::SYNTAX)
.num_args(1)
.group("vm-config"),
)
.arg(
Arg::new("pvpanic")
.long("pvpanic")
.help("Enable pvpanic device")
.num_args(0)
.action(ArgAction::SetTrue)
.group("vm-config"),
)
.arg(
Arg::new("numa")
.long("numa")
.help(config::NumaConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
)
.arg(
Arg::new("watchdog")
.long("watchdog")
.help("Enable virtio-watchdog")
.num_args(0)
.action(ArgAction::SetTrue)
.group("vm-config"),
)
.arg(
Arg::new("v")
.short('v')
.action(ArgAction::Count)
.help("Sets the level of debugging output")
.group("logging"),
)
.arg(
Arg::new("log-file")
.long("log-file")
.help("Log file. Standard error is used if not specified")
.num_args(1)
.group("logging"),
)
.arg(
Arg::new("api-socket")
.long("api-socket")
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
.num_args(1)
.group("vmm-config"),
)
.arg(
Arg::new("event-monitor")
.long("event-monitor")
.help("File to report events on: path=</path/to/a/file> or fd=<fd>")
.num_args(1)
.group("vmm-config"),
)
.arg(
Arg::new("restore")
.long("restore")
.help(config::RestoreConfig::SYNTAX)
.num_args(1)
.group("vmm-config"),
)
.arg(
Arg::new("seccomp")
.long("seccomp")
.num_args(1)
.value_parser(["true", "false", "log"])
.default_value("true"),
)
.arg(
Arg::new("tpm")
.long("tpm")
.num_args(1)
.help(config::TpmConfig::SYNTAX)
.group("vmm-config"),
);
#[cfg(target_arch = "x86_64")] #[argh(option, long = "platform")]
let app = app.arg( /// num_pci_segments=<num_pci_segments>, iommu_segments=<list_of_segments>, serial_number=<dmi_device_serial_number>, uuid=<dmi_device_uuid>, oem_strings=<list_of_strings>
Arg::new("sgx-epc") platform: Option<String>,
.long("sgx-epc")
.help(config::SgxEpcConfig::SYNTAX)
.num_args(1..)
.group("vm-config"),
);
#[cfg(feature = "guest_debug")] #[argh(option, long = "memory", default = "default_memory()")]
let app = app.arg( /// size=<guest_memory_size>, mergeable=on|off, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, hotplug_method=acpi|virtio-mem, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off, thp=on|off
Arg::new("gdb") memory: String,
.long("gdb")
.help("GDB socket (UNIX domain socket): path=</path/to/a/file>") #[argh(option, long = "memory-zone")]
.num_args(1) /// size=<guest_memory_region_size>, file=<backing_file>, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, host_numa_node=<node_id>, id=<zone_identifier>, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off
.group("vmm-config"), memory_zone: Vec<String>,
);
#[argh(option, long = "firmware")]
/// path to firmware that is loaded in an architectural specific way
firmware: Option<String>,
#[argh(option, long = "kernel")]
/// path to kernel or firmware that supports a PVH entry point or architecture equivalent
kernel: Option<String>,
#[argh(option, long = "initramfs")]
/// path to initramfs image
initramfs: Option<String>,
#[argh(option, long = "cmdline")]
/// kernel command line
cmdline: Option<String>,
#[argh(option, long = "disk")]
/// path=<disk_image_path>, readonly=on|off, direct=on|off, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, vhost_user=on|off, socket=<vhost_user_socket_path>, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, id=<device_id>, pci_segment=<segment_id>
disk: Vec<String>,
#[argh(option, long = "net")]
/// tap=<if_name>, ip=<ip_addr>, mask=<net_mask>, mac=<mac_addr>, fd=<fd1,fd2...>, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, vhost_user=<vhost_user_enable>, socket=<vhost_user_socket_path>, vhost_mode=client|server, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, pci_segment=<segment_id>, offload_tso=on|off, offload_ufo=on|off, offload_csum=on|off
net: Vec<String>,
#[argh(option, long = "rng", default = "default_rng()")]
/// src=<entropy_source_path>, iommu=on|off
rng: String,
#[argh(option, long = "balloon")]
/// size=<balloon_size>, deflate_on_oom=on|off, free_page_reporting=on|off
balloon: Option<String>,
#[argh(option, long = "fs")]
/// tag=<tag_name>, socket=<socket_path>, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, pci_segment=<segment_id>
fs: Vec<String>,
#[argh(option, long = "pmem")]
/// file=<backing_file_path>, size=<persistent_memory_size>, iommu=on|off, discard_writes=on|off, id=<device_id>, pci_segment=<segment_id>
pmem: Vec<String>,
#[argh(option, long = "serial", default = "String::from(\"null\")")]
/// off|null|pty|tty|file=/path/to/a/file
serial: String,
#[argh(option, long = "console", default = "String::from(\"tty\")")]
/// off|null|pty|tty|file=/path/to/a/file, iommu=on|off
console: String,
#[argh(option, long = "device")]
/// path=<device_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
device: Vec<String>,
#[argh(option, long = "user-device")]
/// socket=<socket_path>, id=<device_id>, pci_segment=<segment_id>
user_device: Vec<String>,
#[argh(option, long = "vdpa")]
/// path=<device_path>, num_queues=<number_of_queues>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
vdpa: Vec<String>,
#[argh(option, long = "vsock")]
/// cid=<context_id>, socket=<socket_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
vsock: Option<String>,
#[argh(switch, long = "pvpanic")]
/// enable pvpanic device
pvpanic: bool,
#[argh(option, long = "numa")]
/// guest_numa_id=<node_id>, cpus=<cpus_id>, distances=<list_of_distances_to_destination_nodes>, memory_zones=<list_of_memory_zones>, sgx_epc_sections=<list_of_sgx_epc_sections>
numa: Vec<String>,
#[argh(switch, long = "watchdog")]
/// enable virtio-watchdog
watchdog: bool,
#[argh(switch, short = 'v')]
/// set the level of debugging output
verbosity: u8,
#[argh(option, long = "log-file")]
/// path to log file
log_file: Option<String>,
#[argh(option, long = "api-socket")]
/// path=<path/to/a/file>|fd=<fd>
api_socket: Option<String>,
#[cfg(feature = "dbus_api")] #[cfg(feature = "dbus_api")]
let app = app #[argh(option, long = "dbus-service-name")]
.arg( /// well known name of the service
Arg::new("dbus-service-name") dbus_name: Option<String>,
.long("dbus-service-name")
.help("Well known name of the device") #[cfg(feature = "dbus_api")]
.num_args(1) #[argh(option, long = "dbus-object-path")]
.group("vmm-config"), /// object path to serve the dbus interface
) dbus_path: Option<String>,
.arg(
Arg::new("dbus-object-path") #[cfg(feature = "dbus_api")]
.long("dbus-object-path") #[argh(switch, long = "dbus-system-bus")]
.help("Object path to serve the dbus interface") /// use the system bus instead of a session bus
.num_args(1) dbus_system_bus: bool,
.group("vmm-config"),
) #[argh(option, long = "event-monitor")]
.arg( /// path=<path/to/a/file>|fd=<fd>
Arg::new("dbus-system-bus") event_monitor: Option<String>,
.long("dbus-system-bus")
.action(ArgAction::SetTrue) #[argh(option, long = "restore")]
.help("Use the system bus instead of a session bus") /// source_url=<source_url>, prefault=on|off
.num_args(0) restore: Option<String>,
.group("vmm-config"),
); #[argh(option, long = "seccomp", default = "String::from(\"true\")")]
#[cfg(feature = "igvm")] /// seccomp configuration (true, false or log)
let app = app.arg( seccomp: String,
Arg::new("igvm")
.long("igvm") #[argh(option, long = "tpm")]
.help("Path to IGVM file to load.") /// socket=<path/to/a/socket>
.num_args(1) tpm: Option<String>,
.group("vm-config"),
); #[cfg(target_arch = "x86_64")]
app.arg( #[argh(option, long = "sgx-epc")]
Arg::new("version") /// id=<epc_section_identifier>, size=<epc_section_size>, prefault=on|off
.short('V') sgx_epc: Vec<String>,
.long("version")
.action(ArgAction::SetTrue) #[cfg(feature = "guest_debug")]
.help("Print version") #[argh(option, long = "gdb")]
.num_args(0), /// path=<path/to/a/file>
) gdb: Option<String>,
#[argh(switch, short = 'V', long = "version")]
/// print version information
version: bool,
} }
fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> { impl TopLevel {
let log_level = match cmd_arguments.get_count("v") { fn to_vm_params(&self) -> config::VmParams<'_> {
let cpus = &self.cpus;
let memory = &self.memory;
let memory_zones = if !self.memory_zone.is_empty() {
Some(self.memory_zone.iter().map(|x| x.as_str()).collect())
} else {
None
};
let rng = &self.rng;
let serial = &self.serial;
let firmware = self.firmware.as_deref();
let kernel = self.kernel.as_deref();
let initramfs = self.initramfs.as_deref();
let cmdline = self.cmdline.as_deref();
let disks = if !self.disk.is_empty() {
Some(self.disk.iter().map(|x| x.as_str()).collect())
} else {
None
};
let net = if !self.net.is_empty() {
Some(self.net.iter().map(|x| x.as_str()).collect())
} else {
None
};
let console = &self.console;
let balloon = self.balloon.as_deref();
let fs = if !self.fs.is_empty() {
Some(self.fs.iter().map(|x| x.as_str()).collect())
} else {
None
};
let pmem = if !self.pmem.is_empty() {
Some(self.pmem.iter().map(|x| x.as_str()).collect())
} else {
None
};
let devices = if !self.device.is_empty() {
Some(self.device.iter().map(|x| x.as_str()).collect())
} else {
None
};
let user_devices = if !self.user_device.is_empty() {
Some(self.user_device.iter().map(|x| x.as_str()).collect())
} else {
None
};
let vdpa = if !self.vdpa.is_empty() {
Some(self.vdpa.iter().map(|x| x.as_str()).collect())
} else {
None
};
let vsock = self.vsock.as_deref();
let pvpanic = self.pvpanic;
#[cfg(target_arch = "x86_64")]
let sgx_epc = if !self.sgx_epc.is_empty() {
Some(self.sgx_epc.iter().map(|x| x.as_str()).collect())
} else {
None
};
let numa = if !self.numa.is_empty() {
Some(self.numa.iter().map(|x| x.as_str()).collect())
} else {
None
};
let watchdog = self.watchdog;
let platform = self.platform.as_deref();
#[cfg(feature = "guest_debug")]
let gdb = self.gdb.is_some();
let tpm = self.tpm.as_deref();
config::VmParams {
cpus,
memory,
memory_zones,
firmware,
kernel,
initramfs,
cmdline,
disks,
net,
rng,
balloon,
fs,
pmem,
serial,
console,
devices,
user_devices,
vdpa,
vsock,
pvpanic,
#[cfg(target_arch = "x86_64")]
sgx_epc,
numa,
watchdog,
#[cfg(feature = "guest_debug")]
gdb,
platform,
tpm,
}
}
}
fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
let log_level = match toplevel.verbosity {
0 => LevelFilter::Warn, 0 => LevelFilter::Warn,
1 => LevelFilter::Info, 1 => LevelFilter::Info,
2 => LevelFilter::Debug, 2 => LevelFilter::Debug,
_ => LevelFilter::Trace, _ => LevelFilter::Trace,
}; };
let log_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = let log_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = toplevel.log_file {
cmd_arguments.get_one::<String>("log-file")
{
Box::new(std::fs::File::create(std::path::Path::new(file)).map_err(Error::LogFileCreation)?) Box::new(std::fs::File::create(std::path::Path::new(file)).map_err(Error::LogFileCreation)?)
} else { } else {
Box::new(std::io::stderr()) Box::new(std::io::stderr())
@@ -484,47 +430,37 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
.map(|()| log::set_max_level(log_level)) .map(|()| log::set_max_level(log_level))
.map_err(Error::LoggerSetup)?; .map_err(Error::LoggerSetup)?;
let (api_socket_path, api_socket_fd) = let (api_socket_path, api_socket_fd) = if let Some(ref socket_config) = toplevel.api_socket {
if let Some(socket_config) = cmd_arguments.get_one::<String>("api-socket") { let mut parser = OptionParser::new();
let mut parser = OptionParser::new(); parser.add("path").add("fd");
parser.add("path").add("fd"); parser.parse(socket_config).unwrap_or_default();
parser.parse(socket_config).unwrap_or_default();
if let Some(fd) = parser.get("fd") { if let Some(fd) = parser.get("fd") {
( (
None, None,
Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?), Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?),
) )
} else if let Some(path) = parser.get("path") { } else if let Some(path) = parser.get("path") {
(Some(path), None) (Some(path), None)
} else {
(
cmd_arguments
.get_one::<String>("api-socket")
.map(|s| s.to_string()),
None,
)
}
} else { } else {
(None, None) (toplevel.api_socket.as_ref().map(|s| s.to_string()), None)
}; }
} else {
(None, None)
};
let (api_request_sender, api_request_receiver) = channel(); let (api_request_sender, api_request_receiver) = channel();
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?; let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?;
let api_request_sender_clone = api_request_sender.clone(); let api_request_sender_clone = api_request_sender.clone();
let seccomp_action = if let Some(seccomp_value) = cmd_arguments.get_one::<String>("seccomp") { let seccomp_action = match &toplevel.seccomp as &str {
match seccomp_value as &str { "true" => SeccompAction::Trap,
"true" => SeccompAction::Trap, "false" => SeccompAction::Allow,
"false" => SeccompAction::Allow, "log" => SeccompAction::Log,
"log" => SeccompAction::Log, val => {
val => { // The user providing an invalid value will be rejected
// The user providing an invalid value will be rejected panic!("Invalid parameter {val} for \"--seccomp\" flag");
panic!("Invalid parameter {val} for \"--seccomp\" flag");
}
} }
} else {
SeccompAction::Trap
}; };
if seccomp_action == SeccompAction::Trap { if seccomp_action == SeccompAction::Trap {
@@ -562,7 +498,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?; let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
let gdb_socket_path = if let Some(gdb_config) = cmd_arguments.get_one::<String>("gdb") { let gdb_socket_path = if let Some(ref gdb_config) = toplevel.gdb {
let mut parser = OptionParser::new(); let mut parser = OptionParser::new();
parser.add("path"); parser.add("path");
parser.parse(gdb_config).map_err(Error::ParsingGdb)?; parser.parse(gdb_config).map_err(Error::ParsingGdb)?;
@@ -583,8 +519,8 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?; let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
#[allow(unused_mut)] #[allow(unused_mut)]
let mut event_monitor = cmd_arguments let mut event_monitor = toplevel
.get_one::<String>("event-monitor") .event_monitor
.as_ref() .as_ref()
.map(|monitor_config| { .map(|monitor_config| {
let mut parser = OptionParser::new(); let mut parser = OptionParser::new();
@@ -605,7 +541,6 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
std::fs::OpenOptions::new() std::fs::OpenOptions::new()
.write(true) .write(true)
.create(true) .create(true)
.truncate(true)
.open(parser.get("path").unwrap()) .open(parser.get("path").unwrap())
.map_err(Error::EventMonitorIo)?, .map_err(Error::EventMonitorIo)?,
)) ))
@@ -620,11 +555,8 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
.transpose()?; .transpose()?;
#[cfg(feature = "dbus_api")] #[cfg(feature = "dbus_api")]
let dbus_options = match ( let dbus_options = match (&toplevel.dbus_name, &toplevel.dbus_path) {
cmd_arguments.get_one::<String>("dbus-service-name"), (Some(ref name), Some(ref path)) => {
cmd_arguments.get_one::<String>("dbus-object-path"),
) {
(Some(name), Some(path)) => {
// monitor is either set (file based) or not. // monitor is either set (file based) or not.
// if it's not set, create one without file support. // if it's not set, create one without file support.
let mut monitor = match event_monitor.take() { let mut monitor = match event_monitor.take() {
@@ -632,9 +564,9 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
None => event_monitor::set_monitor(None).map_err(Error::EventMonitorIo)?, None => event_monitor::set_monitor(None).map_err(Error::EventMonitorIo)?,
}; };
let options = DBusApiOptions { let options = DBusApiOptions {
service_name: name.to_string(), service_name: name.to_owned(),
object_path: path.to_string(), object_path: path.to_owned(),
system_bus: cmd_arguments.get_flag("dbus-system-bus"), system_bus: toplevel.dbus_system_bus,
event_monitor_rx: monitor.subscribe(), event_monitor_rx: monitor.subscribe(),
}; };
@@ -680,11 +612,10 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
.map_err(Error::StartVmmThread)?; .map_err(Error::StartVmmThread)?;
let r: Result<(), Error> = (|| { let r: Result<(), Error> = (|| {
let payload_present = let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
cmd_arguments.contains_id("kernel") || cmd_arguments.contains_id("firmware");
if payload_present { if payload_present {
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments); let vm_params = toplevel.to_vm_params();
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?; 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. // Create and boot the VM based off the VM config we just built.
@@ -696,12 +627,12 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
) )
.map_err(Error::VmCreate)?; .map_err(Error::VmCreate)?;
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?; vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
} else if let Some(restore_params) = cmd_arguments.get_one::<String>("restore") { } else if let Some(restore_params) = toplevel.restore {
vmm::api::vm_restore( vmm::api::vm_restore(
api_evt.try_clone().unwrap(), api_evt.try_clone().unwrap(),
api_request_sender, api_request_sender,
Arc::new( Arc::new(
config::RestoreConfig::parse(restore_params).map_err(Error::ParsingRestore)?, config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?,
), ),
) )
.map_err(Error::VmRestore)?; .map_err(Error::VmRestore)?;
@@ -741,20 +672,14 @@ fn main() {
// SAFETY: trivially safe // SAFETY: trivially safe
let _ = unsafe { libc::umask(0o077) }; let _ = unsafe { libc::umask(0o077) };
let (default_vcpus, default_memory, default_rng) = prepare_default_values(); let toplevel: TopLevel = argh::from_env();
let cmd_arguments = create_app(default_vcpus, default_memory, default_rng).get_matches();
if cmd_arguments.get_flag("version") { if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
if cmd_arguments.get_count("v") != 0 {
println!("Enabled features: {:?}", vmm::feature_list());
}
return; return;
} }
let exit_code = match start_vmm(cmd_arguments) { let exit_code = match start_vmm(toplevel) {
Ok(path) => { Ok(path) => {
path.map(|s| std::fs::remove_file(s).ok()); path.map(|s| std::fs::remove_file(s).ok());
0 0
@@ -774,18 +699,45 @@ fn main() {
#[cfg(test)] #[cfg(test)]
mod unit_tests { mod unit_tests {
use crate::config::HotplugMethod; use crate::config::HotplugMethod;
use crate::{create_app, prepare_default_values}; use crate::TopLevel;
use std::path::PathBuf; use std::path::PathBuf;
use vmm::config::{ use vmm::config::{
ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, MemoryConfig, PayloadConfig, ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, MemoryConfig, PayloadConfig,
RngConfig, VmConfig, VmParams, RngConfig, VmConfig,
}; };
// Taken from argh
fn cmd<'a>(default: &'a str, path: &'a str) -> &'a str {
std::path::Path::new(path)
.file_name()
.and_then(|s| s.to_str())
.unwrap_or(default)
}
// Some code taken from argh since it does not provide a helper to parse arbitrary strings
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig { fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
let (default_vcpus, default_memory, default_rng) = prepare_default_values(); let strings: Vec<String> = args.iter().map(|x| x.to_string()).collect();
let cmd_arguments = let cmd = cmd(&strings[0], &strings[0]);
create_app(default_vcpus, default_memory, default_rng).get_matches_from(args); let strs: Vec<&str> = strings.iter().map(|s| s.as_str()).collect();
let vm_params = VmParams::from_arg_matches(&cmd_arguments); let toplevel = <TopLevel as argh::FromArgs>::from_args(&[cmd], &strs[1..]).unwrap_or_else(
|early_exit| {
std::process::exit(match early_exit.status {
Ok(()) => {
println!("{}", early_exit.output);
0
}
Err(()) => {
eprintln!(
"{}\nRun {} --help for more information.",
early_exit.output, cmd
);
1
}
})
},
);
let vm_params = toplevel.to_vm_params();
VmConfig::parse(vm_params).unwrap() VmConfig::parse(vm_params).unwrap()
} }
@@ -856,13 +808,11 @@ mod unit_tests {
file: None, file: None,
mode: ConsoleOutputMode::Null, mode: ConsoleOutputMode::Null,
iommu: false, iommu: false,
socket: None,
}, },
console: ConsoleConfig { console: ConsoleConfig {
file: None, file: None,
mode: ConsoleOutputMode::Tty, mode: ConsoleOutputMode::Tty,
iommu: false, iommu: false,
socket: None,
}, },
devices: None, devices: None,
user_devices: None, user_devices: None,
@@ -1048,6 +998,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--disk", "--disk",
"path=/path/to/disk/1", "path=/path/to/disk/1",
"--disk",
"path=/path/to/disk/2", "path=/path/to/disk/2",
], ],
r#"{ r#"{
@@ -1066,6 +1017,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--disk", "--disk",
"path=/path/to/disk/1", "path=/path/to/disk/1",
"--disk",
"path=/path/to/disk/2", "path=/path/to/disk/2",
], ],
r#"{ r#"{
@@ -1340,6 +1292,7 @@ mod unit_tests {
"--memory", "shared=true", "--memory", "shared=true",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1", "tag=virtiofs1,socket=/path/to/sock1",
"--fs",
"tag=virtiofs2,socket=/path/to/sock2", "tag=virtiofs2,socket=/path/to/sock2",
], ],
r#"{ r#"{
@@ -1358,6 +1311,7 @@ mod unit_tests {
"--memory", "shared=true", "--memory", "shared=true",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1", "tag=virtiofs1,socket=/path/to/sock1",
"--fs",
"tag=virtiofs2,socket=/path/to/sock2", "tag=virtiofs2,socket=/path/to/sock2",
], ],
r#"{ r#"{
@@ -1419,6 +1373,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--pmem", "--pmem",
"file=/path/to/img/1,size=1G", "file=/path/to/img/1,size=1G",
"--pmem",
"file=/path/to/img/2,size=2G", "file=/path/to/img/2,size=2G",
], ],
r#"{ r#"{
@@ -1585,6 +1540,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--device", "--device",
"path=/path/to/device/1", "path=/path/to/device/1",
"--device",
"path=/path/to/device/2", "path=/path/to/device/2",
], ],
r#"{ r#"{
@@ -1603,6 +1559,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--device", "--device",
"path=/path/to/device/1", "path=/path/to/device/1",
"--device",
"path=/path/to/device/2", "path=/path/to/device/2",
], ],
r#"{ r#"{
@@ -1679,6 +1636,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--vdpa", "--vdpa",
"path=/path/to/device/1", "path=/path/to/device/1",
"--vdpa",
"path=/path/to/device/2,num_queues=2", "path=/path/to/device/2,num_queues=2",
], ],
r#"{ r#"{
@@ -1697,6 +1655,7 @@ mod unit_tests {
"/path/to/kernel", "/path/to/kernel",
"--vdpa", "--vdpa",
"path=/path/to/device/1", "path=/path/to/device/1",
"--vdpa",
"path=/path/to/device/2", "path=/path/to/device/2",
], ],
r#"{ r#"{

View File

@@ -47,7 +47,7 @@ write_files:
# 1G ram requires 512 pages # 1G ram requires 512 pages
echo 512 | sudo tee /proc/sys/vm/nr_hugepages echo 512 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
/mnt/cloud-hypervisor --kernel /mnt/vmlinux --cmdline "console=hvc0 reboot=k panic=1 nomodules root=/dev/vda1 VFIOTAG" --disk path=/mnt/focal-server-cloudimg-amd64-custom-20210609-0.raw path=/mnt/cloudinit.img --cpus boot=1 --memory size=512M,hotplug_size=1G,hugepages=on --device path=/sys/bus/pci/devices/0000:00:05.0/ path=/sys/bus/pci/devices/0000:00:07.0/ path=/sys/bus/pci/devices/0000:00:08.0/ --api-socket=/tmp/ch_api.sock /mnt/cloud-hypervisor --kernel /mnt/vmlinux --cmdline "console=hvc0 reboot=k panic=1 nomodules root=/dev/vda1 VFIOTAG" --disk path=/mnt/focal-server-cloudimg-amd64-custom-20210609-0.raw --disk path=/mnt/cloudinit.img --cpus boot=1 --memory size=512M,hotplug_size=1G,hugepages=on --device path=/sys/bus/pci/devices/0000:00:05.0/ --device path=/sys/bus/pci/devices/0000:00:07.0/ --device path=/sys/bus/pci/devices/0000:00:08.0/ --api-socket /tmp/ch_api.sock
- -
path: /etc/systemd/system/notify-booted.service path: /etc/systemd/system/notify-booted.service

View File

@@ -12,5 +12,5 @@ once_cell = "1.18.0"
serde = { version = "1.0.168", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -149,13 +149,13 @@ impl GuestNetworkConfig {
Err(e) => { Err(e) => {
let duration = start.elapsed(); let duration = start.elapsed();
eprintln!( eprintln!(
"\n\n==== Start 'wait_vm_boot' (FAILED) ==== \ "\n\n==== Start 'wait_vm_boot' (FAILED) ====\n\n\
\n\nduration =\"{duration:?}, timeout = {timeout}s\" \ duration =\"{duration:?}, timeout = {timeout}s\"\n\
\nlisten_addr=\"{listen_addr}\" \ listen_addr=\"{listen_addr}\"\n\
\nexpected_guest_addr=\"{expected_guest_addr}\" \ expected_guest_addr=\"{expected_guest_addr}\"\n\
\nmessage=\"{s}\" \ message=\"{s}\"\n\
\nerror=\"{e:?}\" \ error=\"{e:?}\"\n\
\n\n==== End 'wait_vm_boot' outout ====\n\n" \n==== End 'wait_vm_boot' outout ====\n\n"
); );
Err(e) Err(e)
@@ -724,77 +724,18 @@ pub fn ssh_command_ip(
) )
} }
pub fn exec_host_command_with_retries(command: &str, retries: u32, interval: Duration) -> bool {
for _ in 0..retries {
let s = exec_host_command_output(command).status;
if !s.success() {
eprintln!("\n\n==== retrying in {:?} ===\n\n", interval);
thread::sleep(interval);
} else {
return true;
}
}
false
}
pub fn exec_host_command_status(command: &str) -> ExitStatus { pub fn exec_host_command_status(command: &str) -> ExitStatus {
exec_host_command_output(command).status std::process::Command::new("bash")
.args(["-c", command])
.status()
.unwrap_or_else(|_| panic!("Expected '{command}' to run"))
} }
pub fn exec_host_command_output(command: &str) -> Output { pub fn exec_host_command_output(command: &str) -> Output {
let output = std::process::Command::new("bash") std::process::Command::new("bash")
.args(["-c", command]) .args(["-c", command])
.output() .output()
.unwrap_or_else(|e| panic!("Expected '{command}' to run. Error: {:?}", e)); .unwrap_or_else(|_| panic!("Expected '{command}' to run"))
if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!(
"\n\n==== Start 'exec_host_command' failed ==== \
\n\n---stdout---\n{stdout}\n---stderr---{stderr} \
\n\n==== End 'exec_host_command' failed ====",
);
}
output
}
pub fn check_lines_count(input: &str, line_count: usize) -> bool {
if input.lines().count() == line_count {
true
} else {
eprintln!(
"\n\n==== Start 'check_lines_count' failed ==== \
\n\ninput = {input}\nline_count = {line_count} \
\n\n==== End 'check_lines_count' failed ====",
);
false
}
}
pub fn check_matched_lines_count(input: &str, keywords: Vec<&str>, line_count: usize) -> bool {
let mut matches = String::new();
for line in input.lines() {
if keywords.iter().all(|k| line.contains(k)) {
matches += line;
}
}
if matches.lines().count() == line_count {
true
} else {
eprintln!(
"\n\n==== Start 'check_matched_lines_count' failed ==== \
\nkeywords = {keywords:?}, line_count = {line_count} \
\n\ninput = {input} matches = {matches} \
\n\n==== End 'check_matched_lines_count' failed ====",
);
false
}
} }
pub const PIPE_SIZE: i32 = 32 << 20; pub const PIPE_SIZE: i32 = 32 << 20;
@@ -1217,7 +1158,7 @@ impl ToString for VerbosityLevel {
match self { match self {
Warn => "".to_string(), Warn => "".to_string(),
Info => "-v".to_string(), Info => "-v".to_string(),
Debug => "-vv".to_string(), Debug => "-v -v".to_string(),
} }
} }
} }
@@ -1268,7 +1209,7 @@ impl<'a> GuestCommand<'a> {
self.command.arg("-v"); self.command.arg("-v");
} }
Debug => { Debug => {
self.command.args(["-vv"]); self.command.args(["-v", "-v"]);
} }
}; };
@@ -1336,6 +1277,7 @@ impl<'a> GuestCommand<'a> {
.unwrap() .unwrap()
) )
.as_str(), .as_str(),
"--disk",
format!( format!(
"path={}", "path={}",
self.guest.disk_config.disk(DiskType::CloudInit).unwrap() self.guest.disk_config.disk(DiskType::CloudInit).unwrap()
@@ -1402,7 +1344,7 @@ pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Resu
}) })
.map_err(|_| { .map_err(|_| {
eprintln!( eprintln!(
"==== Start iperf3 output ===\n\n{}\n\n=== End iperf3 output ===\n\n", "=============== iperf3 output ===============\n\n{}\n\n===========end============\n\n",
String::from_utf8_lossy(output) String::from_utf8_lossy(output)
); );
Error::Iperf3Parse Error::Iperf3Parse
@@ -1480,7 +1422,9 @@ pub fn parse_fio_output(output: &str, fio_ops: &FioOps, num_jobs: u32) -> Result
total_bps total_bps
}) })
.map_err(|_| { .map_err(|_| {
eprintln!("=== Start Fio output ===\n\n{output}\n\n=== End Fio output ===\n\n"); eprintln!(
"=============== Fio output ===============\n\n{output}\n\n===========end============\n\n"
);
Error::FioOutputParse Error::FioOutputParse
}) })
} }
@@ -1533,7 +1477,9 @@ pub fn parse_fio_output_iops(output: &str, fio_ops: &FioOps, num_jobs: u32) -> R
total_iops total_iops
}) })
.map_err(|_| { .map_err(|_| {
eprintln!("=== Start Fio output ===\n\n{output}\n\n=== End Fio output ===\n\n"); eprintln!(
"=============== Fio output ===============\n\n{output}\n\n===========end============\n\n"
);
Error::FioOutputParse Error::FioOutputParse
}) })
} }
@@ -1666,7 +1612,7 @@ pub fn parse_ethr_latency_output(output: &[u8]) -> Result<Vec<f64>, Error> {
}) })
.map_err(|_| { .map_err(|_| {
eprintln!( eprintln!(
"=== Start ethr output ===\n\n{}\n\n=== End ethr output ===\n\n", "=============== ethr output ===============\n\n{}\n\n===========end============\n\n",
String::from_utf8_lossy(output) String::from_utf8_lossy(output)
); );
Error::EthrLogParse Error::EthrLogParse

File diff suppressed because it is too large Load Diff

View File

@@ -12,4 +12,4 @@ libc = "0.2.138"
log = "0.4.17" log = "0.4.17"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
thiserror = "1.0.37" thiserror = "1.0.37"
vmm-sys-util = "0.12.1" vmm-sys-util = "0.11.0"

View File

@@ -6,7 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.147" libc = "0.2.147"
log = "0.4.20" log = "0.4.17"
once_cell = "1.18.0" once_cell = "1.18.0"
serde = { version = "1.0.168", features = ["rc", "derive"] } serde = { version = "1.0.168", features = ["rc", "derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"

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