aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.d/containers.yml5
-rw-r--r--.gitlab-ci.d/static_checks.yml21
-rw-r--r--docs/devel/testing.rst26
-rw-r--r--hw/i386/pc.c6
-rw-r--r--linux-headers/linux/kvm.h8
-rw-r--r--python/.gitignore16
-rw-r--r--python/MANIFEST.in3
-rw-r--r--python/Makefile48
-rw-r--r--python/PACKAGE.rst43
-rw-r--r--python/Pipfile13
-rw-r--r--python/Pipfile.lock231
-rw-r--r--python/README.rst58
-rw-r--r--python/VERSION1
-rw-r--r--python/avocado.cfg10
-rw-r--r--python/mypy.ini4
-rw-r--r--python/qemu/.flake82
-rw-r--r--python/qemu/.isort.cfg7
-rw-r--r--python/qemu/README.rst8
-rw-r--r--python/qemu/__init__.py11
-rw-r--r--python/qemu/machine/README.rst9
-rw-r--r--python/qemu/machine/__init__.py36
-rw-r--r--python/qemu/machine/console_socket.py (renamed from python/qemu/console_socket.py)11
-rw-r--r--python/qemu/machine/machine.py (renamed from python/qemu/machine.py)68
-rw-r--r--python/qemu/machine/qtest.py (renamed from python/qemu/qtest.py)9
-rw-r--r--python/qemu/pylintrc58
-rw-r--r--python/qemu/qmp/README.rst9
-rw-r--r--python/qemu/qmp/__init__.py (renamed from python/qemu/qmp.py)12
-rw-r--r--python/qemu/utils/README.rst7
-rw-r--r--python/qemu/utils/__init__.py45
-rw-r--r--python/qemu/utils/accel.py (renamed from python/qemu/accel.py)0
-rw-r--r--python/setup.cfg102
-rwxr-xr-xpython/setup.py23
-rwxr-xr-xpython/tests/flake8.sh2
-rwxr-xr-xpython/tests/isort.sh2
-rwxr-xr-xpython/tests/mypy.sh2
-rwxr-xr-xpython/tests/pylint.sh2
-rw-r--r--qapi/misc-target.json38
-rw-r--r--target/i386/cpu-dump.c63
-rw-r--r--target/i386/cpu-sysemu.c2
-rw-r--r--target/i386/cpu.c290
-rw-r--r--target/i386/cpu.h6
-rw-r--r--target/i386/kvm/kvm-cpu.c5
-rw-r--r--target/i386/kvm/kvm.c510
-rw-r--r--target/i386/monitor.c6
-rw-r--r--target/i386/sev-stub.c7
-rw-r--r--target/i386/sev.c115
-rw-r--r--target/i386/sev_i386.h2
-rw-r--r--target/i386/trace-events1
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py69
-rw-r--r--tests/acceptance/boot_linux.py18
-rw-r--r--tests/acceptance/hotplug_cpu.py37
-rw-r--r--tests/acceptance/info_usernet.py29
-rw-r--r--tests/acceptance/linux_ssh_mips_malta.py42
-rw-r--r--tests/acceptance/virtio-gpu.py2
-rw-r--r--tests/acceptance/virtiofs_submounts.py71
-rw-r--r--tests/docker/dockerfiles/python.docker18
-rwxr-xr-xtests/qemu-iotests/2971
-rwxr-xr-xtests/qemu-iotests/3004
-rw-r--r--tests/qemu-iotests/iotests.py4
-rw-r--r--tests/requirements.txt2
-rw-r--r--tests/vm/aarch64vm.py2
-rw-r--r--tests/vm/basevm.py12
62 files changed, 1581 insertions, 693 deletions
diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml
index a369bb1..cd06d3f 100644
--- a/.gitlab-ci.d/containers.yml
+++ b/.gitlab-ci.d/containers.yml
@@ -38,3 +38,8 @@ amd64-opensuse-leap-container:
extends: .container_job_template
variables:
NAME: opensuse-leap
+
+python-container:
+ extends: .container_job_template
+ variables:
+ NAME: python
diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml
index 91247a6..8e30872 100644
--- a/.gitlab-ci.d/static_checks.yml
+++ b/.gitlab-ci.d/static_checks.yml
@@ -24,3 +24,24 @@ check-dco:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never
- when: on_success
+
+check-python-pipenv:
+ stage: test
+ image: $CI_REGISTRY_IMAGE/qemu/python:latest
+ script:
+ - make -C python venv-check
+ variables:
+ GIT_DEPTH: 1
+ needs:
+ job: python-container
+
+check-python-tox:
+ stage: test
+ image: $CI_REGISTRY_IMAGE/qemu/python:latest
+ script:
+ - make -C python check-tox
+ variables:
+ GIT_DEPTH: 1
+ needs:
+ job: python-container
+ allow_failure: true
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index 1da4c4e..4e42392 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -810,6 +810,32 @@ and hypothetical example follows:
At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
shutdown.
+The ``avocado_qemu.LinuxTest`` base test class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``avocado_qemu.LinuxTest`` is further specialization of the
+``avocado_qemu.Test`` class, so it contains all the characteristics of
+the later plus some extra features.
+
+First of all, this base class is intended for tests that need to
+interact with a fully booted and operational Linux guest. At this
+time, it uses a Fedora 31 guest image. The most basic example looks
+like this:
+
+.. code::
+
+ from avocado_qemu import LinuxTest
+
+
+ class SomeTest(LinuxTest):
+
+ def test(self):
+ self.launch_and_wait()
+ self.ssh_command('some_command_to_be_run_in_the_guest')
+
+Please refer to tests that use ``avocado_qemu.LinuxTest`` under
+``tests/acceptance`` for more examples.
+
QEMUMachine
~~~~~~~~~~~
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 8cfaf21..c6d8d0d 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -94,7 +94,11 @@
#include "trace.h"
#include CONFIG_DEVICES
-GlobalProperty pc_compat_6_0[] = {};
+GlobalProperty pc_compat_6_0[] = {
+ { "qemu64" "-" TYPE_X86_CPU, "family", "6" },
+ { "qemu64" "-" TYPE_X86_CPU, "model", "6" },
+ { "qemu64" "-" TYPE_X86_CPU, "stepping", "3" },
+};
const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0);
GlobalProperty pc_compat_5_2[] = {
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 020b62a..897f831 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1591,6 +1591,8 @@ enum sev_cmd_id {
KVM_SEV_DBG_ENCRYPT,
/* Guest certificates commands */
KVM_SEV_CERT_EXPORT,
+ /* Attestation report */
+ KVM_SEV_GET_ATTESTATION_REPORT,
KVM_SEV_NR_MAX,
};
@@ -1643,6 +1645,12 @@ struct kvm_sev_dbg {
__u32 len;
};
+struct kvm_sev_attestation_report {
+ __u8 mnonce[16];
+ __u64 uaddr;
+ __u32 len;
+};
+
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
diff --git a/python/.gitignore b/python/.gitignore
new file mode 100644
index 0000000..272ed22
--- /dev/null
+++ b/python/.gitignore
@@ -0,0 +1,16 @@
+# linter/tooling cache
+.mypy_cache/
+.cache/
+
+# python packaging
+build/
+dist/
+qemu.egg-info/
+
+# editor config
+.idea/
+.vscode/
+
+# virtual environments (pipenv et al)
+.venv/
+.tox/
diff --git a/python/MANIFEST.in b/python/MANIFEST.in
new file mode 100644
index 0000000..7059ad2
--- /dev/null
+++ b/python/MANIFEST.in
@@ -0,0 +1,3 @@
+include VERSION
+include PACKAGE.rst
+exclude README.rst
diff --git a/python/Makefile b/python/Makefile
new file mode 100644
index 0000000..b5621b0
--- /dev/null
+++ b/python/Makefile
@@ -0,0 +1,48 @@
+.PHONY: help venv venv-check check clean distclean develop
+
+help:
+ @echo "python packaging help:"
+ @echo ""
+ @echo "make venv: Create pipenv's virtual environment."
+ @echo " NOTE: Requires Python 3.6 and pipenv."
+ @echo " Will download packages from PyPI."
+ @echo " Hint: (On Fedora): 'sudo dnf install python36 pipenv'"
+ @echo ""
+ @echo "make venv-check: run linters using pipenv's virtual environment."
+ @echo " Hint: If you don't know which test to run, run this one!"
+ @echo ""
+ @echo "make develop: Install deps for 'make check', and"
+ @echo " the qemu libs in editable/development mode."
+ @echo ""
+ @echo "make check: run linters using the current environment."
+ @echo ""
+ @echo "make check-tox: run linters using multiple python versions."
+ @echo ""
+ @echo "make clean: remove package build output."
+ @echo ""
+ @echo "make distclean: remove venv files, qemu package forwarder,"
+ @echo " built distribution files, and everything"
+ @echo " from 'make clean'."
+
+venv: .venv
+.venv: Pipfile.lock
+ @PIPENV_VENV_IN_PROJECT=1 pipenv sync --dev --keep-outdated
+ @touch .venv
+
+venv-check: venv
+ @pipenv run make check
+
+develop:
+ pip3 install -e .[devel]
+
+check:
+ @avocado --config avocado.cfg run tests/
+
+check-tox:
+ @tox
+
+clean:
+ python3 setup.py clean --all
+
+distclean: clean
+ rm -rf qemu.egg-info/ .venv/ .tox/ dist/
diff --git a/python/PACKAGE.rst b/python/PACKAGE.rst
new file mode 100644
index 0000000..b0b86cc
--- /dev/null
+++ b/python/PACKAGE.rst
@@ -0,0 +1,43 @@
+QEMU Python Tooling
+===================
+
+This package provides QEMU tooling used by the QEMU project to build,
+configure, and test QEMU. It is not a fully-fledged SDK and it is subject
+to change at any time.
+
+Usage
+-----
+
+The ``qemu.qmp`` subpackage provides a library for communicating with
+QMP servers. The ``qemu.machine`` subpackage offers rudimentary
+facilities for launching and managing QEMU processes. Refer to each
+package's documentation
+(``>>> help(qemu.qmp)``, ``>>> help(qemu.machine)``)
+for more information.
+
+Contributing
+------------
+
+This package is maintained by John Snow <jsnow@redhat.com> as part of
+the QEMU source tree. Contributions are welcome and follow the `QEMU
+patch submission process
+<https://wiki.qemu.org/Contribute/SubmitAPatch>`_, which involves
+sending patches to the QEMU development mailing list.
+
+John maintains a `GitLab staging branch
+<https://gitlab.com/jsnow/qemu/-/tree/python>`_, and there is an
+official `GitLab mirror <https://gitlab.com/qemu-project/qemu>`_.
+
+Please report bugs on the `QEMU issue tracker
+<https://gitlab.com/qemu-project/qemu/-/issues>`_ and tag ``@jsnow`` in
+the report.
+
+Optional packages necessary for running code quality analysis for this
+package can be installed with the optional dependency group "devel":
+``pip install qemu[devel]``.
+
+``make develop`` can be used to install this package in editable mode
+(to the current environment) *and* bring in testing dependencies in one
+command.
+
+``make check`` can be used to run the available tests.
diff --git a/python/Pipfile b/python/Pipfile
new file mode 100644
index 0000000..e7acb8c
--- /dev/null
+++ b/python/Pipfile
@@ -0,0 +1,13 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+qemu = {editable = true, extras = ["devel"], path = "."}
+
+[packages]
+qemu = {editable = true,path = "."}
+
+[requires]
+python_version = "3.6"
diff --git a/python/Pipfile.lock b/python/Pipfile.lock
new file mode 100644
index 0000000..6e344f5
--- /dev/null
+++ b/python/Pipfile.lock
@@ -0,0 +1,231 @@
+{
+ "_meta": {
+ "hash": {
+ "sha256": "eff562a688ebc6f3ffe67494dbb804b883e2159ad81c4d55d96da9f7aec13e91"
+ },
+ "pipfile-spec": 6,
+ "requires": {
+ "python_version": "3.6"
+ },
+ "sources": [
+ {
+ "name": "pypi",
+ "url": "https://pypi.org/simple",
+ "verify_ssl": true
+ }
+ ]
+ },
+ "default": {
+ "qemu": {
+ "editable": true,
+ "path": "."
+ }
+ },
+ "develop": {
+ "astroid": {
+ "hashes": [
+ "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
+ "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
+ ],
+ "markers": "python_version ~= '3.6'",
+ "version": "==2.5.6"
+ },
+ "avocado-framework": {
+ "hashes": [
+ "sha256:42aa7962df98d6b78d4efd9afa2177226dc630f3d83a2a7d5baf7a0a7da7fa1b",
+ "sha256:d96ae343abf890e1ef3b3a6af5ce49e35f6bded0715770c4acb325bca555c515"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==88.1"
+ },
+ "flake8": {
+ "hashes": [
+ "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b",
+ "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==3.9.2"
+ },
+ "importlib-metadata": {
+ "hashes": [
+ "sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581",
+ "sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d"
+ ],
+ "markers": "python_version < '3.8'",
+ "version": "==4.0.1"
+ },
+ "isort": {
+ "hashes": [
+ "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
+ "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
+ ],
+ "markers": "python_version >= '3.6' and python_version < '4.0'",
+ "version": "==5.8.0"
+ },
+ "lazy-object-proxy": {
+ "hashes": [
+ "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653",
+ "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61",
+ "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2",
+ "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837",
+ "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3",
+ "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43",
+ "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726",
+ "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3",
+ "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587",
+ "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8",
+ "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a",
+ "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd",
+ "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f",
+ "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad",
+ "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4",
+ "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b",
+ "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf",
+ "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981",
+ "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741",
+ "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e",
+ "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
+ "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+ "version": "==1.6.0"
+ },
+ "mccabe": {
+ "hashes": [
+ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
+ "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
+ ],
+ "version": "==0.6.1"
+ },
+ "mypy": {
+ "hashes": [
+ "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e",
+ "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064",
+ "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c",
+ "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4",
+ "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97",
+ "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df",
+ "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8",
+ "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a",
+ "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56",
+ "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7",
+ "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6",
+ "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5",
+ "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a",
+ "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521",
+ "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564",
+ "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49",
+ "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66",
+ "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a",
+ "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119",
+ "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506",
+ "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c",
+ "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"
+ ],
+ "markers": "python_version >= '3.5'",
+ "version": "==0.812"
+ },
+ "mypy-extensions": {
+ "hashes": [
+ "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
+ "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
+ ],
+ "version": "==0.4.3"
+ },
+ "pycodestyle": {
+ "hashes": [
+ "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
+ "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==2.7.0"
+ },
+ "pyflakes": {
+ "hashes": [
+ "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
+ "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==2.3.1"
+ },
+ "pylint": {
+ "hashes": [
+ "sha256:586d8fa9b1891f4b725f587ef267abe2a1bad89d6b184520c7f07a253dd6e217",
+ "sha256:f7e2072654a6b6afdf5e2fb38147d3e2d2d43c89f648637baab63e026481279b"
+ ],
+ "markers": "python_version ~= '3.6'",
+ "version": "==2.8.2"
+ },
+ "qemu": {
+ "editable": true,
+ "path": "."
+ },
+ "toml": {
+ "hashes": [
+ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
+ "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
+ ],
+ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",
+ "version": "==0.10.2"
+ },
+ "typed-ast": {
+ "hashes": [
+ "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace",
+ "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff",
+ "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266",
+ "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528",
+ "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6",
+ "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808",
+ "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4",
+ "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363",
+ "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341",
+ "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04",
+ "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41",
+ "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e",
+ "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3",
+ "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899",
+ "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805",
+ "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c",
+ "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c",
+ "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39",
+ "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a",
+ "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3",
+ "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7",
+ "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f",
+ "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075",
+ "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0",
+ "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40",
+ "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428",
+ "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927",
+ "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3",
+ "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f",
+ "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"
+ ],
+ "markers": "implementation_name == 'cpython' and python_version < '3.8'",
+ "version": "==1.4.3"
+ },
+ "typing-extensions": {
+ "hashes": [
+ "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
+ "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
+ "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
+ ],
+ "markers": "python_version < '3.8'",
+ "version": "==3.10.0.0"
+ },
+ "wrapt": {
+ "hashes": [
+ "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
+ ],
+ "version": "==1.12.1"
+ },
+ "zipp": {
+ "hashes": [
+ "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76",
+ "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==3.4.1"
+ }
+ }
+}
diff --git a/python/README.rst b/python/README.rst
new file mode 100644
index 0000000..dcf9938
--- /dev/null
+++ b/python/README.rst
@@ -0,0 +1,58 @@
+QEMU Python Tooling
+===================
+
+This directory houses Python tooling used by the QEMU project to build,
+configure, and test QEMU. It is organized by namespace (``qemu``), and
+then by package (e.g. ``qemu/machine``, ``qemu/qmp``, etc).
+
+``setup.py`` is used by ``pip`` to install this tooling to the current
+environment. ``setup.cfg`` provides the packaging configuration used by
+``setup.py`` in a setuptools specific format. You will generally invoke
+it by doing one of the following:
+
+1. ``pip3 install .`` will install these packages to your current
+ environment. If you are inside a virtual environment, they will
+ install there. If you are not, it will attempt to install to the
+ global environment, which is **not recommended**.
+
+2. ``pip3 install --user .`` will install these packages to your user's
+ local python packages. If you are inside of a virtual environment,
+ this will fail; you likely want the first invocation above.
+
+If you append the ``-e`` argument, pip will install in "editable" mode;
+which installs a version of the package that installs a forwarder
+pointing to these files, such that the package always reflects the
+latest version in your git tree.
+
+Installing ".[devel]" instead of "." will additionally pull in required
+packages for testing this package. They are not runtime requirements,
+and are not needed to simply use these libraries.
+
+Running ``make develop`` will pull in all testing dependencies and
+install QEMU in editable mode to the current environment.
+
+See `Installing packages using pip and virtual environments
+<https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/>`_
+for more information.
+
+
+Files in this directory
+-----------------------
+
+- ``qemu/`` Python package source directory.
+- ``tests/`` Python package tests directory.
+- ``avocado.cfg`` Configuration for the Avocado test-runner.
+ Used by ``make check`` et al.
+- ``Makefile`` provides some common testing/installation invocations.
+ Try ``make help`` to see available targets.
+- ``MANIFEST.in`` is read by python setuptools, it specifies additional files
+ that should be included by a source distribution.
+- ``PACKAGE.rst`` is used as the README file that is visible on PyPI.org.
+- ``Pipfile`` is used by Pipenv to generate ``Pipfile.lock``.
+- ``Pipfile.lock`` is a set of pinned package dependencies that this package
+ is tested under in our CI suite. It is used by ``make venv-check``.
+- ``README.rst`` you are here!
+- ``VERSION`` contains the PEP-440 compliant version used to describe
+ this package; it is referenced by ``setup.cfg``.
+- ``setup.cfg`` houses setuptools package configuration.
+- ``setup.py`` is the setuptools installer used by pip; See above.
diff --git a/python/VERSION b/python/VERSION
new file mode 100644
index 0000000..c19f3b8
--- /dev/null
+++ b/python/VERSION
@@ -0,0 +1 @@
+0.6.1.0a1
diff --git a/python/avocado.cfg b/python/avocado.cfg
new file mode 100644
index 0000000..10dc6fb
--- /dev/null
+++ b/python/avocado.cfg
@@ -0,0 +1,10 @@
+[simpletests]
+# Don't show stdout/stderr in the test *summary*
+status.failure_fields = ['status']
+
+[job]
+# Don't show the full debug.log output; only select stdout/stderr.
+output.testlogs.logfiles = ['stdout', 'stderr']
+
+# Show full stdout/stderr only on tests that FAIL
+output.testlogs.statuses = ['FAIL']
diff --git a/python/mypy.ini b/python/mypy.ini
deleted file mode 100644
index 1a581c5..0000000
--- a/python/mypy.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[mypy]
-strict = True
-python_version = 3.6
-warn_unused_configs = True
diff --git a/python/qemu/.flake8 b/python/qemu/.flake8
deleted file mode 100644
index 45d8146..0000000
--- a/python/qemu/.flake8
+++ /dev/null
@@ -1,2 +0,0 @@
-[flake8]
-extend-ignore = E722 # Pylint handles this, but smarter. \ No newline at end of file
diff --git a/python/qemu/.isort.cfg b/python/qemu/.isort.cfg
deleted file mode 100644
index 6d0fd6c..0000000
--- a/python/qemu/.isort.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-[settings]
-force_grid_wrap=4
-force_sort_within_sections=True
-include_trailing_comma=True
-line_length=72
-lines_after_imports=2
-multi_line_output=3 \ No newline at end of file
diff --git a/python/qemu/README.rst b/python/qemu/README.rst
new file mode 100644
index 0000000..d04943f
--- /dev/null
+++ b/python/qemu/README.rst
@@ -0,0 +1,8 @@
+QEMU Python Namespace
+=====================
+
+This directory serves as the root of a `Python PEP 420 implicit
+namespace package <https://www.python.org/dev/peps/pep-0420/>`_.
+
+Each directory below is assumed to be an installable Python package that
+is available under the ``qemu.<package>`` namespace.
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
deleted file mode 100644
index 4ca06c3..0000000
--- a/python/qemu/__init__.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# QEMU library
-#
-# Copyright (C) 2015-2016 Red Hat Inc.
-# Copyright (C) 2012 IBM Corp.
-#
-# Authors:
-# Fam Zheng <famz@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-#
diff --git a/python/qemu/machine/README.rst b/python/qemu/machine/README.rst
new file mode 100644
index 0000000..ac2b4ff
--- /dev/null
+++ b/python/qemu/machine/README.rst
@@ -0,0 +1,9 @@
+qemu.machine package
+====================
+
+This package provides core utilities used for testing and debugging
+QEMU. It is used by the iotests, vm tests, acceptance tests, and several
+other utilities in the ./scripts directory. It is not a fully-fledged
+SDK and it is subject to change at any time.
+
+See the documentation in ``__init__.py`` for more information.
diff --git a/python/qemu/machine/__init__.py b/python/qemu/machine/__init__.py
new file mode 100644
index 0000000..728f27a
--- /dev/null
+++ b/python/qemu/machine/__init__.py
@@ -0,0 +1,36 @@
+"""
+QEMU development and testing library.
+
+This library provides a few high-level classes for driving QEMU from a
+test suite, not intended for production use.
+
+- QEMUMachine: Configure and Boot a QEMU VM
+ - QEMUQtestMachine: VM class, with a qtest socket.
+
+- QEMUQtestProtocol: Connect to, send/receive qtest messages.
+"""
+
+# Copyright (C) 2020-2021 John Snow for Red Hat Inc.
+# Copyright (C) 2015-2016 Red Hat Inc.
+# Copyright (C) 2012 IBM Corp.
+#
+# Authors:
+# John Snow <jsnow@redhat.com>
+# Fam Zheng <fam@euphon.net>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+
+# pylint: disable=import-error
+# see: https://github.com/PyCQA/pylint/issues/3624
+# see: https://github.com/PyCQA/pylint/issues/3651
+from .machine import QEMUMachine
+from .qtest import QEMUQtestMachine, QEMUQtestProtocol
+
+
+__all__ = (
+ 'QEMUMachine',
+ 'QEMUQtestProtocol',
+ 'QEMUQtestMachine',
+)
diff --git a/python/qemu/console_socket.py b/python/qemu/machine/console_socket.py
index ac21130..8c4ff59 100644
--- a/python/qemu/console_socket.py
+++ b/python/qemu/machine/console_socket.py
@@ -39,6 +39,7 @@ class ConsoleSocket(socket.socket):
self.connect(address)
self._logfile = None
if file:
+ # pylint: disable=consider-using-with
self._logfile = open(file, "bw")
self._open = True
self._drain_thread = None
@@ -46,11 +47,11 @@ class ConsoleSocket(socket.socket):
self._drain_thread = self._thread_start()
def __repr__(self) -> str:
- s = super().__repr__()
- s = s.rstrip(">")
- s = "%s, logfile=%s, drain_thread=%s>" % (s, self._logfile,
- self._drain_thread)
- return s
+ tmp = super().__repr__()
+ tmp = tmp.rstrip(">")
+ tmp = "%s, logfile=%s, drain_thread=%s>" % (tmp, self._logfile,
+ self._drain_thread)
+ return tmp
def _drain_fn(self) -> None:
"""Drains the socket and runs while the socket is open."""
diff --git a/python/qemu/machine.py b/python/qemu/machine/machine.py
index 6e44bda..b624355 100644
--- a/python/qemu/machine.py
+++ b/python/qemu/machine/machine.py
@@ -38,8 +38,14 @@ from typing import (
Type,
)
-from . import console_socket, qmp
-from .qmp import QMPMessage, QMPReturnValue, SocketAddrT
+from qemu.qmp import ( # pylint: disable=import-error
+ QEMUMonitorProtocol,
+ QMPMessage,
+ QMPReturnValue,
+ SocketAddrT,
+)
+
+from . import console_socket
LOG = logging.getLogger(__name__)
@@ -84,7 +90,7 @@ class QEMUMachine:
args: Sequence[str] = (),
wrapper: Sequence[str] = (),
name: Optional[str] = None,
- test_dir: str = "/var/tmp",
+ base_temp_dir: str = "/var/tmp",
monitor_address: Optional[SocketAddrT] = None,
socket_scm_helper: Optional[str] = None,
sock_dir: Optional[str] = None,
@@ -97,10 +103,10 @@ class QEMUMachine:
@param args: list of extra arguments
@param wrapper: list of arguments used as prefix to qemu binary
@param name: prefix for socket and log file names (default: qemu-PID)
- @param test_dir: where to create socket and log file
+ @param base_temp_dir: default location where temp files are created
@param monitor_address: address for QMP monitor
@param socket_scm_helper: helper program, required for send_fd_scm()
- @param sock_dir: where to create socket (overrides test_dir for sock)
+ @param sock_dir: where to create socket (defaults to base_temp_dir)
@param drain_console: (optional) True to drain console socket to buffer
@param console_log: (optional) path to console log file
@note: Qemu process is not started until launch() is used.
@@ -112,8 +118,8 @@ class QEMUMachine:
self._wrapper = wrapper
self._name = name or "qemu-%d" % os.getpid()
- self._test_dir = test_dir
- self._sock_dir = sock_dir or self._test_dir
+ self._base_temp_dir = base_temp_dir
+ self._sock_dir = sock_dir or self._base_temp_dir
self._socket_scm_helper = socket_scm_helper
if monitor_address is not None:
@@ -139,7 +145,7 @@ class QEMUMachine:
self._events: List[QMPMessage] = []
self._iolog: Optional[str] = None
self._qmp_set = True # Enable QMP monitor by default.
- self._qmp_connection: Optional[qmp.QEMUMonitorProtocol] = None
+ self._qmp_connection: Optional[QEMUMonitorProtocol] = None
self._qemu_full_args: Tuple[str, ...] = ()
self._temp_dir: Optional[str] = None
self._launched = False
@@ -223,14 +229,16 @@ class QEMUMachine:
assert fd is not None
fd_param.append(str(fd))
- devnull = open(os.path.devnull, 'rb')
- proc = subprocess.Popen(
- fd_param, stdin=devnull, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT, close_fds=False
+ proc = subprocess.run(
+ fd_param,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ check=False,
+ close_fds=False,
)
- output = proc.communicate()[0]
- if output:
- LOG.debug(output)
+ if proc.stdout:
+ LOG.debug(proc.stdout)
return proc.returncode
@@ -303,10 +311,7 @@ class QEMUMachine:
return args
def _pre_launch(self) -> None:
- self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
- dir=self._test_dir)
- self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
- self._qemu_log_file = open(self._qemu_log_path, 'wb')
+ self._qemu_log_path = os.path.join(self.temp_dir, self._name + ".log")
if self._console_set:
self._remove_files.append(self._console_address)
@@ -315,12 +320,17 @@ class QEMUMachine:
if self._remove_monitor_sockfile:
assert isinstance(self._monitor_address, str)
self._remove_files.append(self._monitor_address)
- self._qmp_connection = qmp.QEMUMonitorProtocol(
+ self._qmp_connection = QEMUMonitorProtocol(
self._monitor_address,
server=True,
nickname=self._name
)
+ # NOTE: Make sure any opened resources are *definitely* freed in
+ # _post_shutdown()!
+ # pylint: disable=consider-using-with
+ self._qemu_log_file = open(self._qemu_log_path, 'wb')
+
def _post_launch(self) -> None:
if self._qmp_connection:
self._qmp.accept()
@@ -393,7 +403,6 @@ class QEMUMachine:
"""
Launch the VM and establish a QMP connection
"""
- devnull = open(os.path.devnull, 'rb')
self._pre_launch()
self._qemu_full_args = tuple(
chain(self._wrapper,
@@ -402,8 +411,11 @@ class QEMUMachine:
self._args)
)
LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
+
+ # Cleaning up of this subprocess is guaranteed by _do_shutdown.
+ # pylint: disable=consider-using-with
self._popen = subprocess.Popen(self._qemu_full_args,
- stdin=devnull,
+ stdin=subprocess.DEVNULL,
stdout=self._qemu_log_file,
stderr=subprocess.STDOUT,
shell=False,
@@ -535,7 +547,7 @@ class QEMUMachine:
self._qmp_set = enabled
@property
- def _qmp(self) -> qmp.QEMUMonitorProtocol:
+ def _qmp(self) -> QEMUMonitorProtocol:
if self._qmp_connection is None:
raise QEMUMachineError("Attempt to access QMP with no connection")
return self._qmp_connection
@@ -744,3 +756,13 @@ class QEMUMachine:
file=self._console_log_path,
drain=self._drain_console)
return self._console_socket
+
+ @property
+ def temp_dir(self) -> str:
+ """
+ Returns a temporary directory to be used for this machine
+ """
+ if self._temp_dir is None:
+ self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
+ dir=self._base_temp_dir)
+ return self._temp_dir
diff --git a/python/qemu/qtest.py b/python/qemu/machine/qtest.py
index 39a0cf6..9370068 100644
--- a/python/qemu/qtest.py
+++ b/python/qemu/machine/qtest.py
@@ -26,8 +26,9 @@ from typing import (
TextIO,
)
+from qemu.qmp import SocketAddrT # pylint: disable=import-error
+
from .machine import QEMUMachine
-from .qmp import SocketAddrT
class QEMUQtestProtocol:
@@ -112,14 +113,14 @@ class QEMUQtestMachine(QEMUMachine):
binary: str,
args: Sequence[str] = (),
name: Optional[str] = None,
- test_dir: str = "/var/tmp",
+ base_temp_dir: str = "/var/tmp",
socket_scm_helper: Optional[str] = None,
sock_dir: Optional[str] = None):
if name is None:
name = "qemu-%d" % os.getpid()
if sock_dir is None:
- sock_dir = test_dir
- super().__init__(binary, args, name=name, test_dir=test_dir,
+ sock_dir = base_temp_dir
+ super().__init__(binary, args, name=name, base_temp_dir=base_temp_dir,
socket_scm_helper=socket_scm_helper,
sock_dir=sock_dir)
self._qtest: Optional[QEMUQtestProtocol] = None
diff --git a/python/qemu/pylintrc b/python/qemu/pylintrc
deleted file mode 100644
index 3f69205..0000000
--- a/python/qemu/pylintrc
+++ /dev/null
@@ -1,58 +0,0 @@
-[MASTER]
-
-[MESSAGES CONTROL]
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once). You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use "--disable=all --enable=classes
-# --disable=W".
-disable=too-many-arguments,
- too-many-instance-attributes,
- too-many-public-methods,
-
-[REPORTS]
-
-[REFACTORING]
-
-[MISCELLANEOUS]
-
-[LOGGING]
-
-[BASIC]
-
-# Good variable names which should always be accepted, separated by a comma.
-good-names=i,
- j,
- k,
- ex,
- Run,
- _,
- fd,
- c,
-[VARIABLES]
-
-[STRING]
-
-[SPELLING]
-
-[FORMAT]
-
-[SIMILARITIES]
-
-# Ignore imports when computing similarities.
-ignore-imports=yes
-
-[TYPECHECK]
-
-[CLASSES]
-
-[IMPORTS]
-
-[DESIGN]
-
-[EXCEPTIONS]
diff --git a/python/qemu/qmp/README.rst b/python/qemu/qmp/README.rst
new file mode 100644
index 0000000..c219514
--- /dev/null
+++ b/python/qemu/qmp/README.rst
@@ -0,0 +1,9 @@
+qemu.qmp package
+================
+
+This package provides a library used for connecting to and communicating
+with QMP servers. It is used extensively by iotests, vm tests,
+acceptance tests, and other utilities in the ./scripts directory. It is
+not a fully-fledged SDK and is subject to change at any time.
+
+See the documentation in ``__init__.py`` for more information.
diff --git a/python/qemu/qmp.py b/python/qemu/qmp/__init__.py
index 2cd4d43..9606248 100644
--- a/python/qemu/qmp.py
+++ b/python/qemu/qmp/__init__.py
@@ -1,4 +1,14 @@
-""" QEMU Monitor Protocol Python class """
+"""
+QEMU Monitor Protocol (QMP) development library & tooling.
+
+This package provides a fairly low-level class for communicating to QMP
+protocol servers, as implemented by QEMU, the QEMU Guest Agent, and the
+QEMU Storage Daemon. This library is not intended for production use.
+
+`QEMUMonitorProtocol` is the primary class of interest, and all errors
+raised derive from `QMPError`.
+"""
+
# Copyright (C) 2009, 2010 Red Hat Inc.
#
# Authors:
diff --git a/python/qemu/utils/README.rst b/python/qemu/utils/README.rst
new file mode 100644
index 0000000..975fbf4
--- /dev/null
+++ b/python/qemu/utils/README.rst
@@ -0,0 +1,7 @@
+qemu.utils package
+==================
+
+This package provides miscellaneous utilities used for testing and
+debugging QEMU. It is used primarily by the vm and acceptance tests.
+
+See the documentation in ``__init__.py`` for more information.
diff --git a/python/qemu/utils/__init__.py b/python/qemu/utils/__init__.py
new file mode 100644
index 0000000..7f1a513
--- /dev/null
+++ b/python/qemu/utils/__init__.py
@@ -0,0 +1,45 @@
+"""
+QEMU development and testing utilities
+
+This package provides a small handful of utilities for performing
+various tasks not directly related to the launching of a VM.
+"""
+
+# Copyright (C) 2021 Red Hat Inc.
+#
+# Authors:
+# John Snow <jsnow@redhat.com>
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+
+import re
+from typing import Optional
+
+# pylint: disable=import-error
+from .accel import kvm_available, list_accel, tcg_available
+
+
+__all__ = (
+ 'get_info_usernet_hostfwd_port',
+ 'kvm_available',
+ 'list_accel',
+ 'tcg_available',
+)
+
+
+def get_info_usernet_hostfwd_port(info_usernet_output: str) -> Optional[int]:
+ """
+ Returns the port given to the hostfwd parameter via info usernet
+
+ :param info_usernet_output: output generated by hmp command "info usernet"
+ :return: the port number allocated by the hostfwd option
+ """
+ for line in info_usernet_output.split('\r\n'):
+ regex = r'TCP.HOST_FORWARD.*127\.0\.0\.1\s+(\d+)\s+10\.'
+ match = re.search(regex, line)
+ if match is not None:
+ return int(match[1])
+ return None
diff --git a/python/qemu/accel.py b/python/qemu/utils/accel.py
index 297933d..297933d 100644
--- a/python/qemu/accel.py
+++ b/python/qemu/utils/accel.py
diff --git a/python/setup.cfg b/python/setup.cfg
new file mode 100644
index 0000000..0fcdec6
--- /dev/null
+++ b/python/setup.cfg
@@ -0,0 +1,102 @@
+[metadata]
+name = qemu
+version = file:VERSION
+maintainer = QEMU Developer Team
+maintainer_email = qemu-devel@nongnu.org
+url = https://www.qemu.org/
+download_url = https://www.qemu.org/download/
+description = QEMU Python Build, Debug and SDK tooling.
+long_description = file:PACKAGE.rst
+long_description_content_type = text/x-rst
+classifiers =
+ Development Status :: 3 - Alpha
+ License :: OSI Approved :: GNU General Public License v2 (GPLv2)
+ Natural Language :: English
+ Operating System :: OS Independent
+ Programming Language :: Python :: 3 :: Only
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+
+[options]
+python_requires = >= 3.6
+packages =
+ qemu.qmp
+ qemu.machine
+ qemu.utils
+
+[options.extras_require]
+# Run `pipenv lock --dev` when changing these requirements.
+devel =
+ avocado-framework >= 87.0
+ flake8 >= 3.6.0
+ isort >= 5.1.2
+ mypy >= 0.770
+ pylint >= 2.8.0
+ tox >= 3.18.0
+
+[flake8]
+extend-ignore = E722 # Prefer pylint's bare-except checks to flake8's
+exclude = __pycache__,
+ .venv,
+ .tox,
+
+[mypy]
+strict = True
+python_version = 3.6
+warn_unused_configs = True
+namespace_packages = True
+
+[pylint.messages control]
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=too-many-arguments,
+ too-many-instance-attributes,
+ too-many-public-methods,
+
+[pylint.basic]
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _,
+ fd,
+ c,
+
+[pylint.similarities]
+# Ignore imports when computing similarities.
+ignore-imports=yes
+
+[isort]
+force_grid_wrap=4
+force_sort_within_sections=True
+include_trailing_comma=True
+line_length=72
+lines_after_imports=2
+multi_line_output=3
+
+# tox (https://tox.readthedocs.io/) is a tool for running tests in
+# multiple virtualenvs. This configuration file will run the test suite
+# on all supported python versions. To use it, "pip install tox" and
+# then run "tox" from this directory. You will need all of these versions
+# of python available on your system to run this test.
+
+[tox:tox]
+envlist = py36, py37, py38, py39, py310
+
+[testenv]
+allowlist_externals = make
+deps = .[devel]
+commands =
+ make check
diff --git a/python/setup.py b/python/setup.py
new file mode 100755
index 0000000..2014f81
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+"""
+QEMU tooling installer script
+Copyright (c) 2020-2021 John Snow for Red Hat, Inc.
+"""
+
+import setuptools
+import pkg_resources
+
+
+def main():
+ """
+ QEMU tooling installer
+ """
+
+ # https://medium.com/@daveshawley/safely-using-setup-cfg-for-metadata-1babbe54c108
+ pkg_resources.require('setuptools>=39.2')
+
+ setuptools.setup()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/flake8.sh b/python/tests/flake8.sh
new file mode 100755
index 0000000..51e0788
--- /dev/null
+++ b/python/tests/flake8.sh
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+python3 -m flake8
diff --git a/python/tests/isort.sh b/python/tests/isort.sh
new file mode 100755
index 0000000..4480405
--- /dev/null
+++ b/python/tests/isort.sh
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+python3 -m isort -c qemu/
diff --git a/python/tests/mypy.sh b/python/tests/mypy.sh
new file mode 100755
index 0000000..5f980f5
--- /dev/null
+++ b/python/tests/mypy.sh
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+python3 -m mypy -p qemu
diff --git a/python/tests/pylint.sh b/python/tests/pylint.sh
new file mode 100755
index 0000000..4b10b34
--- /dev/null
+++ b/python/tests/pylint.sh
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+python3 -m pylint qemu/
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 6200c67..5573dcf 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -285,3 +285,41 @@
##
{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
'if': 'defined(TARGET_ARM)' }
+
+
+##
+# @SevAttestationReport:
+#
+# The struct describes attestation report for a Secure Encrypted Virtualization
+# feature.
+#
+# @data: guest attestation report (base64 encoded)
+#
+#
+# Since: 6.1
+##
+{ 'struct': 'SevAttestationReport',
+ 'data': { 'data': 'str'},
+ 'if': 'defined(TARGET_I386)' }
+
+##
+# @query-sev-attestation-report:
+#
+# This command is used to get the SEV attestation report, and is supported on AMD
+# X86 platforms only.
+#
+# @mnonce: a random 16 bytes value encoded in base64 (it will be included in report)
+#
+# Returns: SevAttestationReport objects.
+#
+# Since: 6.1
+#
+# Example:
+#
+# -> { "execute" : "query-sev-attestation-report", "arguments": { "mnonce": "aaaaaaa" } }
+# <- { "return" : { "data": "aaaaaaaabbbddddd"} }
+#
+##
+{ 'command': 'query-sev-attestation-report', 'data': { 'mnonce': 'str' },
+ 'returns': 'SevAttestationReport',
+ 'if': 'defined(TARGET_I386)' }
diff --git a/target/i386/cpu-dump.c b/target/i386/cpu-dump.c
index aac21f1..02b635a 100644
--- a/target/i386/cpu-dump.c
+++ b/target/i386/cpu-dump.c
@@ -478,6 +478,11 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
if (flags & CPU_DUMP_FPU) {
int fptag;
+ const uint64_t avx512_mask = XSTATE_OPMASK_MASK | \
+ XSTATE_ZMM_Hi256_MASK | \
+ XSTATE_Hi16_ZMM_MASK | \
+ XSTATE_YMM_MASK | XSTATE_SSE_MASK,
+ avx_mask = XSTATE_YMM_MASK | XSTATE_SSE_MASK;
fptag = 0;
for(i = 0; i < 8; i++) {
fptag |= ((!env->fptags[i]) << i);
@@ -499,21 +504,49 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
else
qemu_fprintf(f, " ");
}
- if (env->hflags & HF_CS64_MASK)
- nb = 16;
- else
- nb = 8;
- for(i=0;i<nb;i++) {
- qemu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
- i,
- env->xmm_regs[i].ZMM_L(3),
- env->xmm_regs[i].ZMM_L(2),
- env->xmm_regs[i].ZMM_L(1),
- env->xmm_regs[i].ZMM_L(0));
- if ((i & 1) == 1)
- qemu_fprintf(f, "\n");
- else
- qemu_fprintf(f, " ");
+
+ if ((env->xcr0 & avx512_mask) == avx512_mask) {
+ /* XSAVE enabled AVX512 */
+ for (i = 0; i < NB_OPMASK_REGS; i++) {
+ qemu_fprintf(f, "Opmask%02d=%016"PRIx64"%s", i,
+ env->opmask_regs[i], ((i & 3) == 3) ? "\n" : " ");
+ }
+
+ nb = (env->hflags & HF_CS64_MASK) ? 32 : 8;
+ for (i = 0; i < nb; i++) {
+ qemu_fprintf(f, "ZMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
+ " %016"PRIx64" %016"PRIx64" %016"PRIx64
+ " %016"PRIx64" %016"PRIx64"\n",
+ i,
+ env->xmm_regs[i].ZMM_Q(7),
+ env->xmm_regs[i].ZMM_Q(6),
+ env->xmm_regs[i].ZMM_Q(5),
+ env->xmm_regs[i].ZMM_Q(4),
+ env->xmm_regs[i].ZMM_Q(3),
+ env->xmm_regs[i].ZMM_Q(2),
+ env->xmm_regs[i].ZMM_Q(1),
+ env->xmm_regs[i].ZMM_Q(0));
+ }
+ } else if ((env->xcr0 & avx_mask) == avx_mask) {
+ /* XSAVE enabled AVX */
+ nb = env->hflags & HF_CS64_MASK ? 16 : 8;
+ for (i = 0; i < nb; i++) {
+ qemu_fprintf(f, "YMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
+ " %016"PRIx64"\n", i,
+ env->xmm_regs[i].ZMM_Q(3),
+ env->xmm_regs[i].ZMM_Q(2),
+ env->xmm_regs[i].ZMM_Q(1),
+ env->xmm_regs[i].ZMM_Q(0));
+ }
+ } else { /* SSE and below cases */
+ nb = env->hflags & HF_CS64_MASK ? 16 : 8;
+ for (i = 0; i < nb; i++) {
+ qemu_fprintf(f, "XMM%02d=%016"PRIx64" %016"PRIx64"%s",
+ i,
+ env->xmm_regs[i].ZMM_Q(1),
+ env->xmm_regs[i].ZMM_Q(0),
+ (i & 1) ? "\n" : " ");
+ }
}
}
if (flags & CPU_DUMP_CODE) {
diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c
index 6477584..1078e3d 100644
--- a/target/i386/cpu-sysemu.c
+++ b/target/i386/cpu-sysemu.c
@@ -312,7 +312,7 @@ GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
CPUX86State *env = &cpu->env;
GuestPanicInformation *panic_info = NULL;
- if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) {
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_CRASH)) {
panic_info = g_malloc0(sizeof(GuestPanicInformation));
panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index b434911..e0ba36c 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -776,94 +776,6 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
*/
.no_autoenable_flags = ~0U,
},
- /*
- * .feat_names are commented out for Hyper-V enlightenments because we
- * don't want to have two different ways for enabling them on QEMU command
- * line. Some features (e.g. "hyperv_time", "hyperv_vapic", ...) require
- * enabling several feature bits simultaneously, exposing these bits
- * individually may just confuse guests.
- */
- [FEAT_HYPERV_EAX] = {
- .type = CPUID_FEATURE_WORD,
- .feat_names = {
- NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */,
- NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */,
- NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */,
- NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */,
- NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */,
- NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */,
- NULL /* hv_msr_debug_access */, NULL /* hv_msr_reenlightenment_access */,
- NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- },
- .cpuid = { .eax = 0x40000003, .reg = R_EAX, },
- },
- [FEAT_HYPERV_EBX] = {
- .type = CPUID_FEATURE_WORD,
- .feat_names = {
- NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */,
- NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */,
- NULL /* hv_post_messages */, NULL /* hv_signal_events */,
- NULL /* hv_create_port */, NULL /* hv_connect_port */,
- NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */,
- NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */,
- NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- },
- .cpuid = { .eax = 0x40000003, .reg = R_EBX, },
- },
- [FEAT_HYPERV_EDX] = {
- .type = CPUID_FEATURE_WORD,
- .feat_names = {
- NULL /* hv_mwait */, NULL /* hv_guest_debugging */,
- NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */,
- NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */,
- NULL, NULL,
- NULL, NULL, NULL /* hv_guest_crash_msr */, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- },
- .cpuid = { .eax = 0x40000003, .reg = R_EDX, },
- },
- [FEAT_HV_RECOMM_EAX] = {
- .type = CPUID_FEATURE_WORD,
- .feat_names = {
- NULL /* hv_recommend_pv_as_switch */,
- NULL /* hv_recommend_pv_tlbflush_local */,
- NULL /* hv_recommend_pv_tlbflush_remote */,
- NULL /* hv_recommend_msr_apic_access */,
- NULL /* hv_recommend_msr_reset */,
- NULL /* hv_recommend_relaxed_timing */,
- NULL /* hv_recommend_dma_remapping */,
- NULL /* hv_recommend_int_remapping */,
- NULL /* hv_recommend_x2apic_msrs */,
- NULL /* hv_recommend_autoeoi_deprecation */,
- NULL /* hv_recommend_pv_ipi */,
- NULL /* hv_recommend_ex_hypercalls */,
- NULL /* hv_hypervisor_is_nested */,
- NULL /* hv_recommend_int_mbec */,
- NULL /* hv_recommend_evmcs */,
- NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- },
- .cpuid = { .eax = 0x40000004, .reg = R_EAX, },
- },
- [FEAT_HV_NESTED_EAX] = {
- .type = CPUID_FEATURE_WORD,
- .cpuid = { .eax = 0x4000000A, .reg = R_EAX, },
- },
[FEAT_SVM] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
@@ -1576,7 +1488,7 @@ typedef struct X86CPUDefinition {
int stepping;
FeatureWordArray features;
const char *model_id;
- CPUCaches *cache_info;
+ const CPUCaches *const cache_info;
/*
* Definitions for alternative versions of CPU model.
* List is terminated by item with version == 0.
@@ -1589,7 +1501,7 @@ typedef struct X86CPUDefinition {
/* Reference to a specific CPU model version */
struct X86CPUModel {
/* Base CPU definition */
- X86CPUDefinition *cpudef;
+ const X86CPUDefinition *cpudef;
/* CPU model version */
X86CPUVersion version;
const char *note;
@@ -1601,14 +1513,15 @@ struct X86CPUModel {
};
/* Get full model name for CPU version */
-static char *x86_cpu_versioned_model_name(X86CPUDefinition *cpudef,
+static char *x86_cpu_versioned_model_name(const X86CPUDefinition *cpudef,
X86CPUVersion version)
{
assert(version > 0);
return g_strdup_printf("%s-v%d", cpudef->name, (int)version);
}
-static const X86CPUVersionDefinition *x86_cpu_def_get_versions(X86CPUDefinition *def)
+static const X86CPUVersionDefinition *
+x86_cpu_def_get_versions(const X86CPUDefinition *def)
{
/* When X86CPUDefinition::versions is NULL, we register only v1 */
static const X86CPUVersionDefinition default_version_list[] = {
@@ -1619,7 +1532,7 @@ static const X86CPUVersionDefinition *x86_cpu_def_get_versions(X86CPUDefinition
return def->versions ?: default_version_list;
}
-static CPUCaches epyc_cache_info = {
+static const CPUCaches epyc_cache_info = {
.l1d_cache = &(CPUCacheInfo) {
.type = DATA_CACHE,
.level = 1,
@@ -1669,7 +1582,7 @@ static CPUCaches epyc_cache_info = {
},
};
-static CPUCaches epyc_rome_cache_info = {
+static const CPUCaches epyc_rome_cache_info = {
.l1d_cache = &(CPUCacheInfo) {
.type = DATA_CACHE,
.level = 1,
@@ -1719,7 +1632,7 @@ static CPUCaches epyc_rome_cache_info = {
},
};
-static CPUCaches epyc_milan_cache_info = {
+static const CPUCaches epyc_milan_cache_info = {
.l1d_cache = &(CPUCacheInfo) {
.type = DATA_CACHE,
.level = 1,
@@ -1797,14 +1710,14 @@ static CPUCaches epyc_milan_cache_info = {
* PT in VMX operation
*/
-static X86CPUDefinition builtin_x86_defs[] = {
+static const X86CPUDefinition builtin_x86_defs[] = {
{
.name = "qemu64",
.level = 0xd,
.vendor = CPUID_VENDOR_AMD,
- .family = 6,
- .model = 6,
- .stepping = 3,
+ .family = 15,
+ .model = 107,
+ .stepping = 1,
.features[FEAT_1_EDX] =
PPRO_FEATURES |
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
@@ -2802,12 +2715,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
CPUID_7_0_EBX_SMAP,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 4 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -2883,6 +2791,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 4,
+ .note = "IBRS, XSAVES, no TSX",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ }
+ },
{ /* end of list */ }
}
},
@@ -2922,12 +2839,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT,
.features[FEAT_7_0_ECX] =
CPUID_7_0_ECX_PKU,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 5 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3015,6 +2927,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 5,
+ .note = "IBRS, XSAVES, EPT switching, no TSX",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ }
+ },
{ /* end of list */ }
}
},
@@ -3057,12 +2978,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_ECX_AVX512VNNI,
.features[FEAT_7_0_EDX] =
CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 5 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3146,6 +3062,14 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
},
},
+ { .version = 5,
+ .note = "ARCH_CAPABILITIES, EPT switching, XSAVES, no TSX",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ },
+ },
{ /* end of list */ }
}
},
@@ -3195,13 +3119,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO,
.features[FEAT_7_1_EAX] =
CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16,
- /*
- * Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 2 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3257,6 +3175,18 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING,
.xlevel = 0x80000008,
.model_id = "Intel Xeon Processor (Cooperlake)",
+ .versions = (X86CPUVersionDefinition[]) {
+ { .version = 1 },
+ { .version = 2,
+ .note = "XSAVES",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ },
+ },
+ { /* end of list */ }
+ }
},
{
.name = "Icelake-Client",
@@ -3299,12 +3229,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_ECX_AVX512_VPOPCNTDQ,
.features[FEAT_7_0_EDX] =
CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 3 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3372,6 +3297,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
},
},
+ {
+ .version = 3,
+ .note = "no TSX, XSAVES, deprecated",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ },
+ },
{ /* end of list */ }
},
.deprecation_note = "use Icelake-Server instead"
@@ -3420,12 +3354,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57,
.features[FEAT_7_0_EDX] =
CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD,
- /* Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 5 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3518,6 +3447,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
},
},
+ {
+ .version = 5,
+ .note = "XSAVES",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ }
+ },
+ },
{ /* end of list */ }
}
},
@@ -3552,13 +3490,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_7_0_EDX] =
CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES |
CPUID_7_0_EDX_SPEC_CTRL_SSBD,
- /*
- * Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is added in version 3 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | CPUID_XSAVE_XGETBV1,
.features[FEAT_6_EAX] =
@@ -3625,6 +3557,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ },
},
},
+ {
+ .version = 3,
+ .note = "XSAVES, no MPX, no MONITOR",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ },
+ },
+ },
{ /* end of list */ },
},
},
@@ -3683,13 +3624,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EDX_CORE_CAPABILITY,
.features[FEAT_CORE_CAPABILITY] =
MSR_CORE_CAP_SPLIT_LOCK_DETECT,
- /*
- * Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component,
- * and the only one defined in Skylake (processor tracing)
- * probably will block migration anyway.
- */
+ /* XSAVES is is added in version 3 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -3754,6 +3689,15 @@ static X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ },
},
},
+ {
+ .version = 3,
+ .note = "XSAVES, no MPX",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { "vmx-xsaves", "on" },
+ { /* end of list */ },
+ },
+ },
{ /* end of list */ },
},
},
@@ -4035,11 +3979,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT,
- /*
- * Missing: XSAVES (not supported by some Linux versions,
- * including v4.1 to v4.12).
- * KVM doesn't yet expose any XSAVES state save component.
- */
+ /* XSAVES is added in version 2 */
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
@@ -4050,6 +3990,17 @@ static X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x8000001E,
.model_id = "Hygon Dhyana Processor",
.cache_info = &epyc_cache_info,
+ .versions = (X86CPUVersionDefinition[]) {
+ { .version = 1 },
+ { .version = 2,
+ .note = "XSAVES",
+ .props = (PropValue[]) {
+ { "xsaves", "on" },
+ { /* end of list */ }
+ },
+ },
+ { /* end of list */ }
+ }
},
{
.name = "EPYC-Rome",
@@ -4246,9 +4197,15 @@ static void max_x86_cpu_initfn(Object *obj)
*/
object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
&error_abort);
+#ifdef TARGET_X86_64
+ object_property_set_int(OBJECT(cpu), "family", 15, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", 107, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", 1, &error_abort);
+#else
object_property_set_int(OBJECT(cpu), "family", 6, &error_abort);
object_property_set_int(OBJECT(cpu), "model", 6, &error_abort);
object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort);
+#endif
object_property_set_str(OBJECT(cpu), "model-id",
"QEMU TCG CPU version " QEMU_HW_VERSION,
&error_abort);
@@ -5023,7 +4980,7 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model)
*/
static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
{
- X86CPUDefinition *def = model->cpudef;
+ const X86CPUDefinition *def = model->cpudef;
CPUX86State *env = &cpu->env;
FeatureWord w;
@@ -5110,7 +5067,7 @@ static void x86_register_cpu_model_type(const char *name, X86CPUModel *model)
type_register(&ti);
}
-static void x86_register_cpudef_types(X86CPUDefinition *def)
+static void x86_register_cpudef_types(const X86CPUDefinition *def)
{
X86CPUModel *m;
const X86CPUVersionDefinition *vdef;
@@ -6096,17 +6053,16 @@ static void x86_cpu_hyperv_realize(X86CPU *cpu)
/* Hyper-V vendor id */
if (!cpu->hyperv_vendor) {
- memcpy(cpu->hyperv_vendor_id, "Microsoft Hv", 12);
- } else {
- len = strlen(cpu->hyperv_vendor);
-
- if (len > 12) {
- warn_report("hv-vendor-id truncated to 12 characters");
- len = 12;
- }
- memset(cpu->hyperv_vendor_id, 0, 12);
- memcpy(cpu->hyperv_vendor_id, cpu->hyperv_vendor, len);
+ object_property_set_str(OBJECT(cpu), "hv-vendor-id", "Microsoft Hv",
+ &error_abort);
+ }
+ len = strlen(cpu->hyperv_vendor);
+ if (len > 12) {
+ warn_report("hv-vendor-id truncated to 12 characters");
+ len = 12;
}
+ memset(cpu->hyperv_vendor_id, 0, 12);
+ memcpy(cpu->hyperv_vendor_id, cpu->hyperv_vendor, len);
/* 'Hv#1' interface identification*/
cpu->hyperv_interface_id[0] = 0x31237648;
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index da72aa5..ac3abea 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -531,11 +531,6 @@ typedef enum FeatureWord {
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
FEAT_KVM_HINTS, /* CPUID[4000_0001].EDX */
- FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
- FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */
- FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */
- FEAT_HV_RECOMM_EAX, /* CPUID[4000_0004].EAX */
- FEAT_HV_NESTED_EAX, /* CPUID[4000_000A].EAX */
FEAT_SVM, /* CPUID[8000_000A].EDX */
FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */
FEAT_6_EAX, /* CPUID[6].EAX */
@@ -1699,6 +1694,7 @@ struct X86CPU {
uint32_t hyperv_interface_id[4];
uint32_t hyperv_version_id[4];
uint32_t hyperv_limits[3];
+ uint32_t hyperv_nested[4];
bool check_cpuid;
bool enforce_cpuid;
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index c660ad4..5235bce 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -47,6 +47,11 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp)
/*
* KVM-specific features that are automatically added/removed
* from all CPU models when KVM is enabled.
+ *
+ * NOTE: features can be enabled by default only if they were
+ * already available in the oldest kernel version supported
+ * by the KVM accelerator (see "OS requirements" section at
+ * docs/system/target-i386.rst)
*/
static PropValue kvm_default_props[] = {
{ "kvmclock", "on" },
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index d972eb4..c676ee8 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -129,6 +129,7 @@ static int has_exception_payload;
static bool has_msr_mcg_ext_ctl;
static struct kvm_cpuid2 *cpuid_cache;
+static struct kvm_cpuid2 *hv_cpuid_cache;
static struct kvm_msr_list *kvm_feature_msrs;
int kvm_has_pit_state2(void)
@@ -715,8 +716,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs)
static bool hyperv_enabled(X86CPU *cpu)
{
- CPUState *cs = CPU(cpu);
- return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 &&
+ return kvm_check_extension(kvm_state, KVM_CAP_HYPERV) > 0 &&
((cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_NOTIFY) ||
cpu->hyperv_features || cpu->hyperv_passthrough);
}
@@ -801,7 +801,8 @@ static bool tsc_is_stable_and_known(CPUX86State *env)
static struct {
const char *desc;
struct {
- uint32_t fw;
+ uint32_t func;
+ int reg;
uint32_t bits;
} flags[2];
uint64_t dependencies;
@@ -809,25 +810,25 @@ static struct {
[HYPERV_FEAT_RELAXED] = {
.desc = "relaxed timing (hv-relaxed)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_HYPERCALL_AVAILABLE},
- {.fw = FEAT_HV_RECOMM_EAX,
+ {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_RELAXED_TIMING_RECOMMENDED}
}
},
[HYPERV_FEAT_VAPIC] = {
.desc = "virtual APIC (hv-vapic)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_HYPERCALL_AVAILABLE | HV_APIC_ACCESS_AVAILABLE},
- {.fw = FEAT_HV_RECOMM_EAX,
+ {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_APIC_ACCESS_RECOMMENDED}
}
},
[HYPERV_FEAT_TIME] = {
.desc = "clocksources (hv-time)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_HYPERCALL_AVAILABLE | HV_TIME_REF_COUNT_AVAILABLE |
HV_REFERENCE_TSC_AVAILABLE}
}
@@ -835,42 +836,42 @@ static struct {
[HYPERV_FEAT_CRASH] = {
.desc = "crash MSRs (hv-crash)",
.flags = {
- {.fw = FEAT_HYPERV_EDX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_GUEST_CRASH_MSR_AVAILABLE}
}
},
[HYPERV_FEAT_RESET] = {
.desc = "reset MSR (hv-reset)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_RESET_AVAILABLE}
}
},
[HYPERV_FEAT_VPINDEX] = {
.desc = "VP_INDEX MSR (hv-vpindex)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_VP_INDEX_AVAILABLE}
}
},
[HYPERV_FEAT_RUNTIME] = {
.desc = "VP_RUNTIME MSR (hv-runtime)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_VP_RUNTIME_AVAILABLE}
}
},
[HYPERV_FEAT_SYNIC] = {
.desc = "synthetic interrupt controller (hv-synic)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_SYNIC_AVAILABLE}
}
},
[HYPERV_FEAT_STIMER] = {
.desc = "synthetic timers (hv-stimer)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_SYNTIMERS_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_TIME)
@@ -878,23 +879,23 @@ static struct {
[HYPERV_FEAT_FREQUENCIES] = {
.desc = "frequency MSRs (hv-frequencies)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_ACCESS_FREQUENCY_MSRS},
- {.fw = FEAT_HYPERV_EDX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_FREQUENCY_MSRS_AVAILABLE}
}
},
[HYPERV_FEAT_REENLIGHTENMENT] = {
.desc = "reenlightenment MSRs (hv-reenlightenment)",
.flags = {
- {.fw = FEAT_HYPERV_EAX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_ACCESS_REENLIGHTENMENTS_CONTROL}
}
},
[HYPERV_FEAT_TLBFLUSH] = {
.desc = "paravirtualized TLB flush (hv-tlbflush)",
.flags = {
- {.fw = FEAT_HV_RECOMM_EAX,
+ {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_REMOTE_TLB_FLUSH_RECOMMENDED |
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
},
@@ -903,7 +904,7 @@ static struct {
[HYPERV_FEAT_EVMCS] = {
.desc = "enlightened VMCS (hv-evmcs)",
.flags = {
- {.fw = FEAT_HV_RECOMM_EAX,
+ {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_ENLIGHTENED_VMCS_RECOMMENDED}
},
.dependencies = BIT(HYPERV_FEAT_VAPIC)
@@ -911,7 +912,7 @@ static struct {
[HYPERV_FEAT_IPI] = {
.desc = "paravirtualized IPI (hv-ipi)",
.flags = {
- {.fw = FEAT_HV_RECOMM_EAX,
+ {.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_CLUSTER_IPI_RECOMMENDED |
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
},
@@ -920,14 +921,15 @@ static struct {
[HYPERV_FEAT_STIMER_DIRECT] = {
.desc = "direct mode synthetic timers (hv-stimer-direct)",
.flags = {
- {.fw = FEAT_HYPERV_EDX,
+ {.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_STIMER_DIRECT_MODE_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_STIMER)
},
};
-static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
+static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max,
+ bool do_sys_ioctl)
{
struct kvm_cpuid2 *cpuid;
int r, size;
@@ -936,7 +938,11 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
cpuid = g_malloc0(size);
cpuid->nent = max;
- r = kvm_vcpu_ioctl(cs, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ if (do_sys_ioctl) {
+ r = kvm_ioctl(kvm_state, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ } else {
+ r = kvm_vcpu_ioctl(cs, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ }
if (r == 0 && cpuid->nent >= max) {
r = -E2BIG;
}
@@ -960,16 +966,38 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
{
struct kvm_cpuid2 *cpuid;
- int max = 7; /* 0x40000000..0x40000005, 0x4000000A */
+ /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000080 leaves */
+ int max = 10;
+ int i;
+ bool do_sys_ioctl;
+
+ do_sys_ioctl =
+ kvm_check_extension(kvm_state, KVM_CAP_SYS_HYPERV_CPUID) > 0;
/*
* When the buffer is too small, KVM_GET_SUPPORTED_HV_CPUID fails with
* -E2BIG, however, it doesn't report back the right size. Keep increasing
* it and re-trying until we succeed.
*/
- while ((cpuid = try_get_hv_cpuid(cs, max)) == NULL) {
+ while ((cpuid = try_get_hv_cpuid(cs, max, do_sys_ioctl)) == NULL) {
max++;
}
+
+ /*
+ * KVM_GET_SUPPORTED_HV_CPUID does not set EVMCS CPUID bit before
+ * KVM_CAP_HYPERV_ENLIGHTENED_VMCS is enabled but we want to get the
+ * information early, just check for the capability and set the bit
+ * manually.
+ */
+ if (!do_sys_ioctl && kvm_check_extension(cs->kvm_state,
+ KVM_CAP_HYPERV_ENLIGHTENED_VMCS) > 0) {
+ for (i = 0; i < cpuid->nent; i++) {
+ if (cpuid->entries[i].function == HV_CPUID_ENLIGHTMENT_INFO) {
+ cpuid->entries[i].eax |= HV_ENLIGHTENED_VMCS_RECOMMENDED;
+ }
+ }
+ }
+
return cpuid;
}
@@ -1066,56 +1094,62 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs)
return cpuid;
}
-static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r)
+static uint32_t hv_cpuid_get_host(CPUState *cs, uint32_t func, int reg)
{
struct kvm_cpuid_entry2 *entry;
- uint32_t func;
- int reg;
+ struct kvm_cpuid2 *cpuid;
- switch (fw) {
- case FEAT_HYPERV_EAX:
- reg = R_EAX;
- func = HV_CPUID_FEATURES;
- break;
- case FEAT_HYPERV_EDX:
- reg = R_EDX;
- func = HV_CPUID_FEATURES;
- break;
- case FEAT_HV_RECOMM_EAX:
- reg = R_EAX;
- func = HV_CPUID_ENLIGHTMENT_INFO;
- break;
- default:
- return -EINVAL;
+ if (hv_cpuid_cache) {
+ cpuid = hv_cpuid_cache;
+ } else {
+ if (kvm_check_extension(kvm_state, KVM_CAP_HYPERV_CPUID) > 0) {
+ cpuid = get_supported_hv_cpuid(cs);
+ } else {
+ cpuid = get_supported_hv_cpuid_legacy(cs);
+ }
+ hv_cpuid_cache = cpuid;
+ }
+
+ if (!cpuid) {
+ return 0;
}
entry = cpuid_find_entry(cpuid, func, 0);
if (!entry) {
- return -ENOENT;
+ return 0;
}
- switch (reg) {
- case R_EAX:
- *r = entry->eax;
- break;
- case R_EDX:
- *r = entry->edx;
- break;
- default:
- return -EINVAL;
+ return cpuid_entry_get_reg(entry, reg);
+}
+
+static bool hyperv_feature_supported(CPUState *cs, int feature)
+{
+ uint32_t func, bits;
+ int i, reg;
+
+ for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
+
+ func = kvm_hyperv_properties[feature].flags[i].func;
+ reg = kvm_hyperv_properties[feature].flags[i].reg;
+ bits = kvm_hyperv_properties[feature].flags[i].bits;
+
+ if (!func) {
+ continue;
+ }
+
+ if ((hv_cpuid_get_host(cs, func, reg) & bits) != bits) {
+ return false;
+ }
}
- return 0;
+ return true;
}
-static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
- int feature)
+static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp)
{
X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- uint32_t r, fw, bits;
uint64_t deps;
- int i, dep_feat;
+ int dep_feat;
if (!hyperv_feat_enabled(cpu, feature) && !cpu->hyperv_passthrough) {
return 0;
@@ -1125,35 +1159,22 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
while (deps) {
dep_feat = ctz64(deps);
if (!(hyperv_feat_enabled(cpu, dep_feat))) {
- fprintf(stderr,
- "Hyper-V %s requires Hyper-V %s\n",
- kvm_hyperv_properties[feature].desc,
- kvm_hyperv_properties[dep_feat].desc);
- return 1;
+ error_setg(errp, "Hyper-V %s requires Hyper-V %s",
+ kvm_hyperv_properties[feature].desc,
+ kvm_hyperv_properties[dep_feat].desc);
+ return 1;
}
deps &= ~(1ull << dep_feat);
}
- for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
- fw = kvm_hyperv_properties[feature].flags[i].fw;
- bits = kvm_hyperv_properties[feature].flags[i].bits;
-
- if (!fw) {
- continue;
- }
-
- if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) {
- if (hyperv_feat_enabled(cpu, feature)) {
- fprintf(stderr,
- "Hyper-V %s is not supported by kernel\n",
- kvm_hyperv_properties[feature].desc);
- return 1;
- } else {
- return 0;
- }
+ if (!hyperv_feature_supported(cs, feature)) {
+ if (hyperv_feat_enabled(cpu, feature)) {
+ error_setg(errp, "Hyper-V %s is not supported by kernel",
+ kvm_hyperv_properties[feature].desc);
+ return 1;
+ } else {
+ return 0;
}
-
- env->features[fw] |= bits;
}
if (cpu->hyperv_passthrough) {
@@ -1163,157 +1184,156 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
return 0;
}
-/*
- * Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent in
- * case of success, errno < 0 in case of failure and 0 when no Hyper-V
- * extentions are enabled.
- */
-static int hyperv_handle_properties(CPUState *cs,
- struct kvm_cpuid_entry2 *cpuid_ent)
+static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
{
X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- struct kvm_cpuid2 *cpuid;
- struct kvm_cpuid_entry2 *c;
- uint32_t cpuid_i = 0;
- int r;
+ uint32_t r = 0;
+ int i, j;
- if (!hyperv_enabled(cpu))
- return 0;
-
- if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ||
- cpu->hyperv_passthrough) {
- uint16_t evmcs_version;
-
- r = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
- (uintptr_t)&evmcs_version);
-
- if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) && r) {
- fprintf(stderr, "Hyper-V %s is not supported by kernel\n",
- kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc);
- return -ENOSYS;
- }
-
- if (!r) {
- env->features[FEAT_HV_RECOMM_EAX] |=
- HV_ENLIGHTENED_VMCS_RECOMMENDED;
- env->features[FEAT_HV_NESTED_EAX] = evmcs_version;
- }
- }
-
- if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_CPUID) > 0) {
- cpuid = get_supported_hv_cpuid(cs);
- } else {
- cpuid = get_supported_hv_cpuid_legacy(cs);
- }
-
- if (cpu->hyperv_passthrough) {
- memcpy(cpuid_ent, &cpuid->entries[0],
- cpuid->nent * sizeof(cpuid->entries[0]));
-
- c = cpuid_find_entry(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, 0);
- if (c) {
- cpu->hyperv_vendor_id[0] = c->ebx;
- cpu->hyperv_vendor_id[1] = c->ecx;
- cpu->hyperv_vendor_id[2] = c->edx;
- }
-
- c = cpuid_find_entry(cpuid, HV_CPUID_INTERFACE, 0);
- if (c) {
- cpu->hyperv_interface_id[0] = c->eax;
- cpu->hyperv_interface_id[1] = c->ebx;
- cpu->hyperv_interface_id[2] = c->ecx;
- cpu->hyperv_interface_id[3] = c->edx;
+ for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties); i++) {
+ if (!hyperv_feat_enabled(cpu, i)) {
+ continue;
}
- c = cpuid_find_entry(cpuid, HV_CPUID_VERSION, 0);
- if (c) {
- cpu->hyperv_version_id[0] = c->eax;
- cpu->hyperv_version_id[1] = c->ebx;
- cpu->hyperv_version_id[2] = c->ecx;
- cpu->hyperv_version_id[3] = c->edx;
- }
+ for (j = 0; j < ARRAY_SIZE(kvm_hyperv_properties[i].flags); j++) {
+ if (kvm_hyperv_properties[i].flags[j].func != func) {
+ continue;
+ }
+ if (kvm_hyperv_properties[i].flags[j].reg != reg) {
+ continue;
+ }
- c = cpuid_find_entry(cpuid, HV_CPUID_FEATURES, 0);
- if (c) {
- env->features[FEAT_HYPERV_EAX] = c->eax;
- env->features[FEAT_HYPERV_EBX] = c->ebx;
- env->features[FEAT_HYPERV_EDX] = c->edx;
+ r |= kvm_hyperv_properties[i].flags[j].bits;
}
+ }
- c = cpuid_find_entry(cpuid, HV_CPUID_IMPLEMENT_LIMITS, 0);
- if (c) {
- cpu->hv_max_vps = c->eax;
- cpu->hyperv_limits[0] = c->ebx;
- cpu->hyperv_limits[1] = c->ecx;
- cpu->hyperv_limits[2] = c->edx;
- }
+ return r;
+}
- c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
- if (c) {
- env->features[FEAT_HV_RECOMM_EAX] = c->eax;
+/*
+ * Expand Hyper-V CPU features. In partucular, check that all the requested
+ * features are supported by the host and the sanity of the configuration
+ * (that all the required dependencies are included). Also, this takes care
+ * of 'hv_passthrough' mode and fills the environment with all supported
+ * Hyper-V features.
+ */
+static void hyperv_expand_features(CPUState *cs, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(cs);
- /* hv-spinlocks may have been overriden */
- if (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_NOTIFY) {
- c->ebx = cpu->hyperv_spinlock_attempts;
- }
- }
- c = cpuid_find_entry(cpuid, HV_CPUID_NESTED_FEATURES, 0);
- if (c) {
- env->features[FEAT_HV_NESTED_EAX] = c->eax;
- }
- }
+ if (!hyperv_enabled(cpu))
+ return;
- if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
- env->features[FEAT_HV_RECOMM_EAX] |= HV_NO_NONARCH_CORESHARING;
- } else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
- c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
- if (c) {
- env->features[FEAT_HV_RECOMM_EAX] |=
- c->eax & HV_NO_NONARCH_CORESHARING;
- }
+ if (cpu->hyperv_passthrough) {
+ cpu->hyperv_vendor_id[0] =
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
+ cpu->hyperv_vendor_id[1] =
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_ECX);
+ cpu->hyperv_vendor_id[2] =
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EDX);
+ cpu->hyperv_vendor = g_realloc(cpu->hyperv_vendor,
+ sizeof(cpu->hyperv_vendor_id) + 1);
+ memcpy(cpu->hyperv_vendor, cpu->hyperv_vendor_id,
+ sizeof(cpu->hyperv_vendor_id));
+ cpu->hyperv_vendor[sizeof(cpu->hyperv_vendor_id)] = 0;
+
+ cpu->hyperv_interface_id[0] =
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EAX);
+ cpu->hyperv_interface_id[1] =
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EBX);
+ cpu->hyperv_interface_id[2] =
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_ECX);
+ cpu->hyperv_interface_id[3] =
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EDX);
+
+ cpu->hyperv_version_id[0] =
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EAX);
+ cpu->hyperv_version_id[1] =
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EBX);
+ cpu->hyperv_version_id[2] =
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_ECX);
+ cpu->hyperv_version_id[3] =
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EDX);
+
+ cpu->hv_max_vps = hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS,
+ R_EAX);
+ cpu->hyperv_limits[0] =
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_EBX);
+ cpu->hyperv_limits[1] =
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_ECX);
+ cpu->hyperv_limits[2] =
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_EDX);
+
+ cpu->hyperv_spinlock_attempts =
+ hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EBX);
}
/* Features */
- r = hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RELAXED);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VAPIC);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TIME);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_CRASH);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RESET);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VPINDEX);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RUNTIME);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_SYNIC);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_FREQUENCIES);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_REENLIGHTENMENT);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TLBFLUSH);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_EVMCS);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_IPI);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER_DIRECT);
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT, errp)) {
+ return;
+ }
/* Additional dependencies not covered by kvm_hyperv_properties[] */
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) &&
!cpu->hyperv_synic_kvm_only &&
!hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX)) {
- fprintf(stderr, "Hyper-V %s requires Hyper-V %s\n",
- kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc,
- kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc);
- r |= 1;
- }
-
- /* Not exposed by KVM but needed to make CPU hotplug in Windows work */
- env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
-
- if (r) {
- r = -ENOSYS;
- goto free;
+ error_setg(errp, "Hyper-V %s requires Hyper-V %s",
+ kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc,
+ kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc);
}
+}
- if (cpu->hyperv_passthrough) {
- /* We already copied all feature words from KVM as is */
- r = cpuid->nent;
- goto free;
- }
+/*
+ * Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent.
+ */
+static int hyperv_fill_cpuids(CPUState *cs,
+ struct kvm_cpuid_entry2 *cpuid_ent)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ struct kvm_cpuid_entry2 *c;
+ uint32_t cpuid_i = 0;
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
@@ -1339,15 +1359,25 @@ static int hyperv_handle_properties(CPUState *cs,
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_FEATURES;
- c->eax = env->features[FEAT_HYPERV_EAX];
- c->ebx = env->features[FEAT_HYPERV_EBX];
- c->edx = env->features[FEAT_HYPERV_EDX];
+ c->eax = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EAX);
+ c->ebx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EBX);
+ c->edx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EDX);
+
+ /* Not exposed by KVM but needed to make CPU hotplug in Windows work */
+ c->edx |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_ENLIGHTMENT_INFO;
- c->eax = env->features[FEAT_HV_RECOMM_EAX];
+ c->eax = hv_build_cpuid_leaf(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EAX);
c->ebx = cpu->hyperv_spinlock_attempts;
+ if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
+ c->eax |= HV_NO_NONARCH_CORESHARING;
+ } else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
+ c->eax |= hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EAX) &
+ HV_NO_NONARCH_CORESHARING;
+ }
+
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_IMPLEMENT_LIMITS;
c->eax = cpu->hv_max_vps;
@@ -1367,14 +1397,10 @@ static int hyperv_handle_properties(CPUState *cs,
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_NESTED_FEATURES;
- c->eax = env->features[FEAT_HV_NESTED_EAX];
+ c->eax = cpu->hyperv_nested[0];
}
- r = cpuid_i;
-
-free:
- g_free(cpuid);
- return r;
+ return cpuid_i;
}
static Error *hv_passthrough_mig_blocker;
@@ -1458,6 +1484,21 @@ static int hyperv_init_vcpu(X86CPU *cpu)
}
}
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) {
+ uint16_t evmcs_version;
+
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
+ (uintptr_t)&evmcs_version);
+
+ if (ret < 0) {
+ fprintf(stderr, "Hyper-V %s is not supported by kernel\n",
+ kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc);
+ return ret;
+ }
+
+ cpu->hyperv_nested[0] = evmcs_version;
+ }
+
return 0;
}
@@ -1516,11 +1557,19 @@ int kvm_arch_init_vcpu(CPUState *cs)
env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY;
/* Paravirtualization CPUIDs */
- r = hyperv_handle_properties(cs, cpuid_data.entries);
- if (r < 0) {
- return r;
- } else if (r > 0) {
- cpuid_i = r;
+ hyperv_expand_features(cs, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -ENOSYS;
+ }
+
+ if (hyperv_enabled(cpu)) {
+ r = hyperv_init_vcpu(cpu);
+ if (r) {
+ return r;
+ }
+
+ cpuid_i = hyperv_fill_cpuids(cs, cpuid_data.entries);
kvm_base = KVM_CPUID_SIGNATURE_NEXT;
has_msr_hv_hypercall = true;
}
@@ -1869,11 +1918,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
kvm_init_msrs(cpu);
- r = hyperv_init_vcpu(cpu);
- if (r) {
- goto fail;
- }
-
return 0;
fail:
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 5994408..119211f 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -757,3 +757,9 @@ void qmp_sev_inject_launch_secret(const char *packet_hdr,
sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
}
+
+SevAttestationReport *
+qmp_query_sev_attestation_report(const char *mnonce, Error **errp)
+{
+ return sev_get_attestation_report(mnonce, errp);
+}
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 0207f1c..0227cb5 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -74,3 +74,10 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
{
abort();
}
+
+SevAttestationReport *
+sev_get_attestation_report(const char *mnonce, Error **errp)
+{
+ error_setg(errp, "SEV is not available in this QEMU");
+ return NULL;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 41f7800..83df8c0 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -87,29 +87,31 @@ static SevGuestState *sev_guest;
static Error *sev_mig_blocker;
static const char *const sev_fw_errlist[] = {
- "",
- "Platform state is invalid",
- "Guest state is invalid",
- "Platform configuration is invalid",
- "Buffer too small",
- "Platform is already owned",
- "Certificate is invalid",
- "Policy is not allowed",
- "Guest is not active",
- "Invalid address",
- "Bad signature",
- "Bad measurement",
- "Asid is already owned",
- "Invalid ASID",
- "WBINVD is required",
- "DF_FLUSH is required",
- "Guest handle is invalid",
- "Invalid command",
- "Guest is active",
- "Hardware error",
- "Hardware unsafe",
- "Feature not supported",
- "Invalid parameter"
+ [SEV_RET_SUCCESS] = "",
+ [SEV_RET_INVALID_PLATFORM_STATE] = "Platform state is invalid",
+ [SEV_RET_INVALID_GUEST_STATE] = "Guest state is invalid",
+ [SEV_RET_INAVLID_CONFIG] = "Platform configuration is invalid",
+ [SEV_RET_INVALID_LEN] = "Buffer too small",
+ [SEV_RET_ALREADY_OWNED] = "Platform is already owned",
+ [SEV_RET_INVALID_CERTIFICATE] = "Certificate is invalid",
+ [SEV_RET_POLICY_FAILURE] = "Policy is not allowed",
+ [SEV_RET_INACTIVE] = "Guest is not active",
+ [SEV_RET_INVALID_ADDRESS] = "Invalid address",
+ [SEV_RET_BAD_SIGNATURE] = "Bad signature",
+ [SEV_RET_BAD_MEASUREMENT] = "Bad measurement",
+ [SEV_RET_ASID_OWNED] = "ASID is already owned",
+ [SEV_RET_INVALID_ASID] = "Invalid ASID",
+ [SEV_RET_WBINVD_REQUIRED] = "WBINVD is required",
+ [SEV_RET_DFFLUSH_REQUIRED] = "DF_FLUSH is required",
+ [SEV_RET_INVALID_GUEST] = "Guest handle is invalid",
+ [SEV_RET_INVALID_COMMAND] = "Invalid command",
+ [SEV_RET_ACTIVE] = "Guest is active",
+ [SEV_RET_HWSEV_RET_PLATFORM] = "Hardware error",
+ [SEV_RET_HWSEV_RET_UNSAFE] = "Hardware unsafe",
+ [SEV_RET_UNSUPPORTED] = "Feature not supported",
+ [SEV_RET_INVALID_PARAM] = "Invalid parameter",
+ [SEV_RET_RESOURCE_LIMIT] = "Required firmware resource depleted",
+ [SEV_RET_SECURE_DATA_INVALID] = "Part-specific integrity check failure",
};
#define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
@@ -492,6 +494,73 @@ out:
return cap;
}
+SevAttestationReport *
+sev_get_attestation_report(const char *mnonce, Error **errp)
+{
+ struct kvm_sev_attestation_report input = {};
+ SevAttestationReport *report = NULL;
+ SevGuestState *sev = sev_guest;
+ guchar *data;
+ guchar *buf;
+ gsize len;
+ int err = 0, ret;
+
+ if (!sev_enabled()) {
+ error_setg(errp, "SEV is not enabled");
+ return NULL;
+ }
+
+ /* lets decode the mnonce string */
+ buf = g_base64_decode(mnonce, &len);
+ if (!buf) {
+ error_setg(errp, "SEV: failed to decode mnonce input");
+ return NULL;
+ }
+
+ /* verify the input mnonce length */
+ if (len != sizeof(input.mnonce)) {
+ error_setg(errp, "SEV: mnonce must be %zu bytes (got %" G_GSIZE_FORMAT ")",
+ sizeof(input.mnonce), len);
+ g_free(buf);
+ return NULL;
+ }
+
+ /* Query the report length */
+ ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+ &input, &err);
+ if (ret < 0) {
+ if (err != SEV_RET_INVALID_LEN) {
+ error_setg(errp, "failed to query the attestation report length "
+ "ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
+ g_free(buf);
+ return NULL;
+ }
+ }
+
+ data = g_malloc(input.len);
+ input.uaddr = (unsigned long)data;
+ memcpy(input.mnonce, buf, sizeof(input.mnonce));
+
+ /* Query the report */
+ ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+ &input, &err);
+ if (ret) {
+ error_setg_errno(errp, errno, "Failed to get attestation report"
+ " ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
+ goto e_free_data;
+ }
+
+ report = g_new0(SevAttestationReport, 1);
+ report->data = g_base64_encode(data, input.len);
+
+ trace_kvm_sev_attestation_report(mnonce, report->data);
+
+e_free_data:
+ g_free(data);
+ g_free(buf);
+ return report;
+}
+
static int
sev_read_file_base64(const char *filename, guchar **data, gsize *len)
{
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index ae221d4..ae6d840 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -35,5 +35,7 @@ extern uint32_t sev_get_cbit_position(void);
extern uint32_t sev_get_reduced_phys_bits(void);
extern char *sev_get_launch_measurement(void);
extern SevCapability *sev_get_capabilities(Error **errp);
+extern SevAttestationReport *
+sev_get_attestation_report(const char *mnonce, Error **errp);
#endif
diff --git a/target/i386/trace-events b/target/i386/trace-events
index f5ecbe2..2cd8726 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -10,3 +10,4 @@ kvm_sev_launch_update_data(void *addr, uint64_t len) "addr %p len 0x%" PRIx64
kvm_sev_launch_measurement(const char *value) "data %s"
kvm_sev_launch_finish(void) ""
kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
+kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index 83b1741..93c4b98 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -20,6 +20,7 @@ import avocado
from avocado.utils import cloudinit
from avocado.utils import datadrainer
from avocado.utils import network
+from avocado.utils import ssh
from avocado.utils import vmimage
from avocado.utils.path import find_command
@@ -40,9 +41,12 @@ else:
sys.path.append(os.path.join(SOURCE_DIR, 'python'))
-from qemu.accel import kvm_available
-from qemu.accel import tcg_available
from qemu.machine import QEMUMachine
+from qemu.utils import (
+ get_info_usernet_hostfwd_port,
+ kvm_available,
+ tcg_available,
+)
def is_readable_executable_file(path):
return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
@@ -253,7 +257,50 @@ class Test(avocado.Test):
cancel_on_missing=cancel_on_missing)
-class LinuxTest(Test):
+class LinuxSSHMixIn:
+ """Contains utility methods for interacting with a guest via SSH."""
+
+ def ssh_connect(self, username, credential, credential_is_key=True):
+ self.ssh_logger = logging.getLogger('ssh')
+ res = self.vm.command('human-monitor-command',
+ command_line='info usernet')
+ port = get_info_usernet_hostfwd_port(res)
+ self.assertIsNotNone(port)
+ self.assertGreater(port, 0)
+ self.log.debug('sshd listening on port: %d', port)
+ if credential_is_key:
+ self.ssh_session = ssh.Session('127.0.0.1', port=port,
+ user=username, key=credential)
+ else:
+ self.ssh_session = ssh.Session('127.0.0.1', port=port,
+ user=username, password=credential)
+ for i in range(10):
+ try:
+ self.ssh_session.connect()
+ return
+ except:
+ time.sleep(4)
+ pass
+ self.fail('ssh connection timeout')
+
+ def ssh_command(self, command):
+ self.ssh_logger.info(command)
+ result = self.ssh_session.cmd(command)
+ stdout_lines = [line.rstrip() for line
+ in result.stdout_text.splitlines()]
+ for line in stdout_lines:
+ self.ssh_logger.info(line)
+ stderr_lines = [line.rstrip() for line
+ in result.stderr_text.splitlines()]
+ for line in stderr_lines:
+ self.ssh_logger.warning(line)
+
+ self.assertEqual(result.exit_status, 0,
+ f'Guest command failed: {command}')
+ return stdout_lines, stderr_lines
+
+
+class LinuxTest(Test, LinuxSSHMixIn):
"""Facilitates having a cloud-image Linux based available.
For tests that indend to interact with guests, this is a better choice
@@ -262,11 +309,16 @@ class LinuxTest(Test):
timeout = 900
chksum = None
+ username = 'root'
+ password = 'password'
- def setUp(self, ssh_pubkey=None):
+ def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
super(LinuxTest, self).setUp()
self.vm.add_args('-smp', '2')
self.vm.add_args('-m', '1024')
+ # The following network device allows for SSH connections
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', '%s,netdev=vnet' % network_device_type)
self.set_up_boot()
if ssh_pubkey is None:
ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
@@ -322,8 +374,8 @@ class LinuxTest(Test):
with open(ssh_pubkey) as pubkey:
pubkey_content = pubkey.read()
cloudinit.iso(cloudinit_iso, self.name,
- username='root',
- password='password',
+ username=self.username,
+ password=self.password,
# QEMU's hard coded usermode router address
phone_home_host='10.0.2.2',
phone_home_port=self.phone_home_port,
@@ -340,7 +392,7 @@ class LinuxTest(Test):
cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
- def launch_and_wait(self):
+ def launch_and_wait(self, set_up_ssh_connection=True):
self.vm.set_console()
self.vm.launch()
console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
@@ -348,3 +400,6 @@ class LinuxTest(Test):
console_drainer.start()
self.log.info('VM launched, waiting for boot confirmation from guest')
cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), self.name)
+ if set_up_ssh_connection:
+ self.log.info('Setting up the SSH connection')
+ self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py
index 0d17803..314370f 100644
--- a/tests/acceptance/boot_linux.py
+++ b/tests/acceptance/boot_linux.py
@@ -29,7 +29,7 @@ class BootLinuxX8664(LinuxTest):
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
def test_pc_i440fx_kvm(self):
"""
@@ -38,7 +38,7 @@ class BootLinuxX8664(LinuxTest):
"""
self.require_accelerator("kvm")
self.vm.add_args("-accel", "kvm")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
def test_pc_q35_tcg(self):
"""
@@ -47,7 +47,7 @@ class BootLinuxX8664(LinuxTest):
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
def test_pc_q35_kvm(self):
"""
@@ -56,7 +56,7 @@ class BootLinuxX8664(LinuxTest):
"""
self.require_accelerator("kvm")
self.vm.add_args("-accel", "kvm")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
class BootLinuxAarch64(LinuxTest):
@@ -85,7 +85,7 @@ class BootLinuxAarch64(LinuxTest):
self.vm.add_args("-cpu", "max")
self.vm.add_args("-machine", "virt,gic-version=2")
self.add_common_args()
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
def test_virt_kvm_gicv2(self):
"""
@@ -98,7 +98,7 @@ class BootLinuxAarch64(LinuxTest):
self.vm.add_args("-cpu", "host")
self.vm.add_args("-machine", "virt,gic-version=2")
self.add_common_args()
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
def test_virt_kvm_gicv3(self):
"""
@@ -111,7 +111,7 @@ class BootLinuxAarch64(LinuxTest):
self.vm.add_args("-cpu", "host")
self.vm.add_args("-machine", "virt,gic-version=3")
self.add_common_args()
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
class BootLinuxPPC64(LinuxTest):
@@ -128,7 +128,7 @@ class BootLinuxPPC64(LinuxTest):
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
class BootLinuxS390X(LinuxTest):
@@ -146,4 +146,4 @@ class BootLinuxS390X(LinuxTest):
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
- self.launch_and_wait()
+ self.launch_and_wait(set_up_ssh_connection=False)
diff --git a/tests/acceptance/hotplug_cpu.py b/tests/acceptance/hotplug_cpu.py
new file mode 100644
index 0000000..6374bf1
--- /dev/null
+++ b/tests/acceptance/hotplug_cpu.py
@@ -0,0 +1,37 @@
+# Functional test that hotplugs a CPU and checks it on a Linux guest
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from avocado_qemu import LinuxTest
+
+
+class HotPlugCPU(LinuxTest):
+
+ def test(self):
+ """
+ :avocado: tags=arch:x86_64
+ :avocado: tags=machine:q35
+ :avocado: tags=accel:kvm
+ """
+ self.require_accelerator('kvm')
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-cpu', 'Haswell')
+ self.vm.add_args('-smp', '1,sockets=1,cores=2,threads=1,maxcpus=2')
+ self.launch_and_wait()
+
+ self.ssh_command('test -e /sys/devices/system/cpu/cpu0')
+ with self.assertRaises(AssertionError):
+ self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
+
+ self.vm.command('device_add',
+ driver='Haswell-x86_64-cpu',
+ socket_id=0,
+ core_id=1,
+ thread_id=0)
+ self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
diff --git a/tests/acceptance/info_usernet.py b/tests/acceptance/info_usernet.py
new file mode 100644
index 0000000..9c1fd90
--- /dev/null
+++ b/tests/acceptance/info_usernet.py
@@ -0,0 +1,29 @@
+# Test for the hmp command "info usernet"
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from avocado_qemu import Test
+
+from qemu.utils import get_info_usernet_hostfwd_port
+
+
+class InfoUsernet(Test):
+
+ def test_hostfwd(self):
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22')
+ self.vm.launch()
+ res = self.vm.command('human-monitor-command',
+ command_line='info usernet')
+ port = get_info_usernet_hostfwd_port(res)
+ self.assertIsNotNone(port,
+ ('"info usernet" output content does not seem to '
+ 'contain the redirected port'))
+ self.assertGreater(port, 0,
+ ('Found a redirected port that is not greater than'
+ ' zero'))
diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py
index 6dbd02d..61c9079 100644
--- a/tests/acceptance/linux_ssh_mips_malta.py
+++ b/tests/acceptance/linux_ssh_mips_malta.py
@@ -12,14 +12,14 @@ import logging
import time
from avocado import skipUnless
-from avocado_qemu import Test
+from avocado_qemu import Test, LinuxSSHMixIn
from avocado_qemu import wait_for_console_pattern
from avocado.utils import process
from avocado.utils import archive
from avocado.utils import ssh
-class LinuxSSH(Test):
+class LinuxSSH(Test, LinuxSSHMixIn):
timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg'
@@ -70,45 +70,9 @@ class LinuxSSH(Test):
def setUp(self):
super(LinuxSSH, self).setUp()
- def get_portfwd(self):
- res = self.vm.command('human-monitor-command',
- command_line='info usernet')
- line = res.split('\r\n')[2]
- port = re.split(r'.*TCP.HOST_FORWARD.*127\.0\.0\.1 (\d+)\s+10\..*',
- line)[1]
- self.log.debug("sshd listening on port:" + port)
- return port
-
- def ssh_connect(self, username, password):
- self.ssh_logger = logging.getLogger('ssh')
- port = self.get_portfwd()
- self.ssh_session = ssh.Session(self.VM_IP, port=int(port),
- user=username, password=password)
- for i in range(10):
- try:
- self.ssh_session.connect()
- return
- except:
- time.sleep(4)
- pass
- self.fail("ssh connection timeout")
-
def ssh_disconnect_vm(self):
self.ssh_session.quit()
- def ssh_command(self, command, is_root=True):
- self.ssh_logger.info(command)
- result = self.ssh_session.cmd(command)
- stdout_lines = [line.rstrip() for line
- in result.stdout_text.splitlines()]
- for line in stdout_lines:
- self.ssh_logger.info(line)
- stderr_lines = [line.rstrip() for line
- in result.stderr_text.splitlines()]
- for line in stderr_lines:
- self.ssh_logger.warning(line)
- return stdout_lines, stderr_lines
-
def boot_debian_wheezy_image_and_ssh_login(self, endianess, kernel_path):
image_url, image_hash = self.get_image_info(endianess)
image_path = self.fetch_asset(image_url, asset_hash=image_hash)
@@ -129,7 +93,7 @@ class LinuxSSH(Test):
wait_for_console_pattern(self, console_pattern, 'Oops')
self.log.info('sshd ready')
- self.ssh_connect('root', 'root')
+ self.ssh_connect('root', 'root', False)
def shutdown_via_ssh(self):
self.ssh_command('poweroff')
diff --git a/tests/acceptance/virtio-gpu.py b/tests/acceptance/virtio-gpu.py
index ab18cdd..e797934 100644
--- a/tests/acceptance/virtio-gpu.py
+++ b/tests/acceptance/virtio-gpu.py
@@ -10,7 +10,7 @@ from avocado_qemu import wait_for_console_pattern
from avocado_qemu import exec_command_and_wait_for_pattern
from avocado_qemu import is_readable_executable_file
-from qemu.accel import kvm_available
+from qemu.utils import kvm_available
import os
import socket
diff --git a/tests/acceptance/virtiofs_submounts.py b/tests/acceptance/virtiofs_submounts.py
index 46fa653..21ad7d7 100644
--- a/tests/acceptance/virtiofs_submounts.py
+++ b/tests/acceptance/virtiofs_submounts.py
@@ -70,56 +70,9 @@ def has_cmds(*cmds):
class VirtiofsSubmountsTest(LinuxTest):
"""
:avocado: tags=arch:x86_64
+ :avocado: tags=accel:kvm
"""
- def get_portfwd(self):
- port = None
-
- res = self.vm.command('human-monitor-command',
- command_line='info usernet')
- for line in res.split('\r\n'):
- match = \
- re.search(r'TCP.HOST_FORWARD.*127\.0\.0\.1\s+(\d+)\s+10\.',
- line)
- if match is not None:
- port = int(match[1])
- break
-
- self.assertIsNotNone(port)
- self.assertGreater(port, 0)
- self.log.debug('sshd listening on port: %d', port)
- return port
-
- def ssh_connect(self, username, keyfile):
- self.ssh_logger = logging.getLogger('ssh')
- port = self.get_portfwd()
- self.ssh_session = ssh.Session('127.0.0.1', port=port,
- user=username, key=keyfile)
- for i in range(10):
- try:
- self.ssh_session.connect()
- return
- except:
- time.sleep(4)
- pass
- self.fail('ssh connection timeout')
-
- def ssh_command(self, command):
- self.ssh_logger.info(command)
- result = self.ssh_session.cmd(command)
- stdout_lines = [line.rstrip() for line
- in result.stdout_text.splitlines()]
- for line in stdout_lines:
- self.ssh_logger.info(line)
- stderr_lines = [line.rstrip() for line
- in result.stderr_text.splitlines()]
- for line in stderr_lines:
- self.ssh_logger.warning(line)
-
- self.assertEqual(result.exit_status, 0,
- f'Guest command failed: {command}')
- return stdout_lines, stderr_lines
-
def run(self, args, ignore_error=False):
stdout, stderr, ret = run_cmd(args)
@@ -181,10 +134,6 @@ class VirtiofsSubmountsTest(LinuxTest):
'-numa',
'node,memdev=mem')
- def launch_vm(self):
- self.launch_and_wait()
- self.ssh_connect('root', self.ssh_key)
-
def set_up_nested_mounts(self):
scratch_dir = os.path.join(self.shared_dir, 'scratch')
try:
@@ -246,18 +195,14 @@ class VirtiofsSubmountsTest(LinuxTest):
self.run(('ssh-keygen', '-N', '', '-t', 'ed25519', '-f', self.ssh_key))
- pubkey = open(self.ssh_key + '.pub').read()
+ pubkey = self.ssh_key + '.pub'
super(VirtiofsSubmountsTest, self).setUp(pubkey)
- if len(vmlinuz) > 0:
+ if vmlinuz:
self.vm.add_args('-kernel', vmlinuz,
'-append', 'console=ttyS0 root=/dev/sda1')
- # Allow us to connect to SSH
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'virtio-net,netdev=vnet')
-
self.require_accelerator("kvm")
self.vm.add_args('-accel', 'kvm')
@@ -277,7 +222,7 @@ class VirtiofsSubmountsTest(LinuxTest):
self.set_up_nested_mounts()
self.set_up_virtiofs()
- self.launch_vm()
+ self.launch_and_wait()
self.mount_in_guest()
self.check_in_guest()
@@ -287,14 +232,14 @@ class VirtiofsSubmountsTest(LinuxTest):
self.set_up_nested_mounts()
- self.launch_vm()
+ self.launch_and_wait()
self.mount_in_guest()
self.check_in_guest()
def test_post_launch_set_up(self):
self.set_up_shared_dir()
self.set_up_virtiofs()
- self.launch_vm()
+ self.launch_and_wait()
self.set_up_nested_mounts()
@@ -304,7 +249,7 @@ class VirtiofsSubmountsTest(LinuxTest):
def test_post_mount_set_up(self):
self.set_up_shared_dir()
self.set_up_virtiofs()
- self.launch_vm()
+ self.launch_and_wait()
self.mount_in_guest()
self.set_up_nested_mounts()
@@ -317,7 +262,7 @@ class VirtiofsSubmountsTest(LinuxTest):
self.set_up_nested_mounts()
self.set_up_virtiofs()
- self.launch_vm()
+ self.launch_and_wait()
self.mount_in_guest()
self.check_in_guest()
diff --git a/tests/docker/dockerfiles/python.docker b/tests/docker/dockerfiles/python.docker
new file mode 100644
index 0000000..56d8841
--- /dev/null
+++ b/tests/docker/dockerfiles/python.docker
@@ -0,0 +1,18 @@
+# Python library testing environment
+
+FROM fedora:latest
+MAINTAINER John Snow <jsnow@redhat.com>
+
+# Please keep this list sorted alphabetically
+ENV PACKAGES \
+ gcc \
+ make \
+ pipenv \
+ python3 \
+ python3-pip \
+ python3-tox \
+ python3-virtualenv \
+ python3.10
+
+RUN dnf install -y $PACKAGES
+RUN rpm -q $PACKAGES | sort > /packages.txt
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
index a37910b..433b732 100755
--- a/tests/qemu-iotests/297
+++ b/tests/qemu-iotests/297
@@ -95,6 +95,7 @@ def run_linters():
'--warn-redundant-casts',
'--warn-unused-ignores',
'--no-implicit-reexport',
+ '--namespace-packages',
filename),
env=env,
check=False,
diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300
index b475a92..fe94de8 100755
--- a/tests/qemu-iotests/300
+++ b/tests/qemu-iotests/300
@@ -28,7 +28,7 @@ import iotests
# Import qemu after iotests.py has amended sys.path
# pylint: disable=wrong-import-order
-import qemu
+from qemu.machine import machine
BlockBitmapMapping = List[Dict[str, object]]
@@ -466,7 +466,7 @@ class TestBlockBitmapMappingErrors(TestDirtyBitmapMigration):
# the failed migration
try:
self.vm_b.shutdown()
- except qemu.machine.AbnormalShutdown:
+ except machine.AbnormalShutdown:
pass
def test_aliased_bitmap_name_too_long(self) -> None:
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 777fa2e..89663da 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -38,7 +38,7 @@ from contextlib import contextmanager
# pylint: disable=import-error, wrong-import-position
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu import qtest
+from qemu.machine import qtest
from qemu.qmp import QMPMessage
# Use this logger for logging messages directly from the iotests module
@@ -571,7 +571,7 @@ class VM(qtest.QEMUQtestMachine):
def __init__(self, path_suffix=''):
name = "qemu%s-%d" % (path_suffix, os.getpid())
super().__init__(qemu_prog, qemu_opts, name=name,
- test_dir=test_dir,
+ base_temp_dir=test_dir,
socket_scm_helper=socket_scm_helper,
sock_dir=sock_dir)
self._num_drives = 0
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 91f3a34..a21b59b 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,5 +1,5 @@
# Add Python module requirements, one per line, to be installed
# in the tests/venv Python virtual environment. For more info,
# refer to: https://pip.pypa.io/en/stable/user_guide/#id1
-avocado-framework==85.0
+avocado-framework==88.1
pycdlib==1.11.0
diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py
index d70ab84..b00cce0 100644
--- a/tests/vm/aarch64vm.py
+++ b/tests/vm/aarch64vm.py
@@ -14,7 +14,7 @@ import os
import sys
import subprocess
import basevm
-from qemu.accel import kvm_available
+from qemu.utils import kvm_available
# This is the config needed for current version of QEMU.
# This works for both kvm and tcg.
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index 00f1d5c..0f2e436 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -19,8 +19,8 @@ import logging
import time
import datetime
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu.accel import kvm_available
from qemu.machine import QEMUMachine
+from qemu.utils import get_info_usernet_hostfwd_port, kvm_available
import subprocess
import hashlib
import argparse
@@ -227,7 +227,7 @@ class BaseVM(object):
"-o", "UserKnownHostsFile=" + os.devnull,
"-o",
"ConnectTimeout={}".format(self._config["ssh_timeout"]),
- "-p", self.ssh_port, "-i", self._ssh_tmp_key_file]
+ "-p", str(self.ssh_port), "-i", self._ssh_tmp_key_file]
# If not in debug mode, set ssh to quiet mode to
# avoid printing the results of commands.
if not self.debug:
@@ -305,12 +305,8 @@ class BaseVM(object):
# Init console so we can start consuming the chars.
self.console_init()
usernet_info = guest.qmp("human-monitor-command",
- command_line="info usernet")
- self.ssh_port = None
- for l in usernet_info["return"].splitlines():
- fields = l.split()
- if "TCP[HOST_FORWARD]" in fields and "22" in fields:
- self.ssh_port = l.split()[3]
+ command_line="info usernet").get("return")
+ self.ssh_port = get_info_usernet_hostfwd_port(usernet_info)
if not self.ssh_port:
raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
usernet_info)