mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 19:03:38 +08:00
* target/i386: new feature bits for AMD processors
* target/i386/tcg: improvements around flag handling * target/i386: add AVX10 support * target/i386: add GraniteRapids-v2 model * dockerfiles: add libcbor * New nitro-enclave machine type * qom: cleanups to object_new * configure: detect 64-bit MIPS for rust * configure: deprecate 32-bit MIPS -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmcjvkQUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroPIKgf/etNpO2T+eLFtWN/Qd5eopBXqNd9k KmeK9EgW9lqx2IPGNen33O+uKpb/TsMmubSsSF+YxTp7pmkc8+71f3rBMaIAD02r /paHSMVw0+f12DAFQz1jdvGihR7Mew0wcF/UdEt737y6vEmPxLTyYG3Gfa4NSZwT /V5jTOIcfUN/UEjNgIp6NTuOEESKmlqt22pfMapgkwMlAJYeeJU2X9eGYE86wJbq ZSXNgK3jL9wGT2XKa3e+OKzHfFpSkrB0JbQbdico9pefnBokN/hTeeUJ81wBAc7u i00W1CEQVJ5lhBc121d4AWMp83ME6HijJUOTMmJbFIONPsITFPHK1CAkng== =D4nR -----END PGP SIGNATURE----- Merge tag 'for-upstream-i386' of https://gitlab.com/bonzini/qemu into staging * target/i386: new feature bits for AMD processors * target/i386/tcg: improvements around flag handling * target/i386: add AVX10 support * target/i386: add GraniteRapids-v2 model * dockerfiles: add libcbor * New nitro-enclave machine type * qom: cleanups to object_new * configure: detect 64-bit MIPS for rust * configure: deprecate 32-bit MIPS # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmcjvkQUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroPIKgf/etNpO2T+eLFtWN/Qd5eopBXqNd9k # KmeK9EgW9lqx2IPGNen33O+uKpb/TsMmubSsSF+YxTp7pmkc8+71f3rBMaIAD02r # /paHSMVw0+f12DAFQz1jdvGihR7Mew0wcF/UdEt737y6vEmPxLTyYG3Gfa4NSZwT # /V5jTOIcfUN/UEjNgIp6NTuOEESKmlqt22pfMapgkwMlAJYeeJU2X9eGYE86wJbq # ZSXNgK3jL9wGT2XKa3e+OKzHfFpSkrB0JbQbdico9pefnBokN/hTeeUJ81wBAc7u # i00W1CEQVJ5lhBc121d4AWMp83ME6HijJUOTMmJbFIONPsITFPHK1CAkng== # =D4nR # -----END PGP SIGNATURE----- # gpg: Signature made Thu 31 Oct 2024 17:28:36 GMT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream-i386' of https://gitlab.com/bonzini/qemu: (49 commits) target/i386: Introduce GraniteRapids-v2 model target/i386: Add AVX512 state when AVX10 is supported target/i386: Add feature dependencies for AVX10 target/i386: add CPUID.24 features for AVX10 target/i386: add AVX10 feature and AVX10 version property target/i386: return bool from x86_cpu_filter_features target/i386: do not rely on ExtSaveArea for accelerator-supported XCR0 bits target/i386: cpu: set correct supported XCR0 features for TCG target/i386: use + to put flags together target/i386: use higher-precision arithmetic to compute CF target/i386: use compiler builtin to compute PF target/i386: make flag variables unsigned target/i386: add a note about gen_jcc1 target/i386: add a few more trivial CCPrepare cases target/i386: optimize TEST+Jxx sequences target/i386: optimize computation of ZF from CC_OP_DYNAMIC target/i386: Wrap cc_op_live with a validity check target/i386: Introduce cc_op_size target/i386: Rearrange CCOp target/i386: remove CC_OP_CLR ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c94bee4cd6
@ -66,7 +66,7 @@
|
|||||||
- source scripts/ci/gitlab-ci-section
|
- source scripts/ci/gitlab-ci-section
|
||||||
- section_start buildenv "Setting up to run tests"
|
- section_start buildenv "Setting up to run tests"
|
||||||
- scripts/git-submodule.sh update roms/SLOF
|
- scripts/git-submodule.sh update roms/SLOF
|
||||||
- meson subprojects download $(cd build/subprojects && echo *)
|
- build/pyvenv/bin/meson subprojects download $(cd build/subprojects && echo *)
|
||||||
- cd build
|
- cd build
|
||||||
- find . -type f -exec touch {} +
|
- find . -type f -exec touch {} +
|
||||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||||
|
@ -115,7 +115,7 @@ build-system-fedora:
|
|||||||
job: amd64-fedora-container
|
job: amd64-fedora-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs --enable-crypto-afalg
|
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs --enable-crypto-afalg --enable-rust
|
||||||
TARGETS: microblaze-softmmu mips-softmmu
|
TARGETS: microblaze-softmmu mips-softmmu
|
||||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
|
@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
|
|||||||
NINJA='/usr/local/bin/ninja'
|
NINJA='/usr/local/bin/ninja'
|
||||||
PACKAGING_COMMAND='pkg'
|
PACKAGING_COMMAND='pkg'
|
||||||
PIP3='/usr/local/bin/pip-3.8'
|
PIP3='/usr/local/bin/pip-3.8'
|
||||||
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk-vnc gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py311-numpy py311-pillow py311-pip py311-pyyaml py311-sphinx py311-sphinx_rtd_theme py311-tomli python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
|
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk-vnc gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py311-numpy py311-pillow py311-pip py311-pyyaml py311-sphinx py311-sphinx_rtd_theme py311-tomli python3 rpm2cpio rust rust-bindgen-cli sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
|
||||||
PYPI_PKGS=''
|
PYPI_PKGS=''
|
||||||
PYTHON='/usr/local/bin/python3'
|
PYTHON='/usr/local/bin/python3'
|
||||||
|
@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake'
|
|||||||
NINJA='/opt/homebrew/bin/ninja'
|
NINJA='/opt/homebrew/bin/ninja'
|
||||||
PACKAGING_COMMAND='brew'
|
PACKAGING_COMMAND='brew'
|
||||||
PIP3='/opt/homebrew/bin/pip3'
|
PIP3='/opt/homebrew/bin/pip3'
|
||||||
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
PKGS='bash bc bindgen bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libcbor libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio rust sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
||||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
||||||
PYTHON='/opt/homebrew/bin/python3'
|
PYTHON='/opt/homebrew/bin/python3'
|
||||||
|
@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake'
|
|||||||
NINJA='/opt/homebrew/bin/ninja'
|
NINJA='/opt/homebrew/bin/ninja'
|
||||||
PACKAGING_COMMAND='brew'
|
PACKAGING_COMMAND='brew'
|
||||||
PIP3='/opt/homebrew/bin/pip3'
|
PIP3='/opt/homebrew/bin/pip3'
|
||||||
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
PKGS='bash bc bindgen bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libcbor libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio rust sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
||||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
||||||
PYTHON='/opt/homebrew/bin/python3'
|
PYTHON='/opt/homebrew/bin/python3'
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
config LINUX
|
config LINUX
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config LIBCBOR
|
||||||
|
bool
|
||||||
|
|
||||||
|
config GNUTLS
|
||||||
|
bool
|
||||||
|
|
||||||
config OPENGL
|
config OPENGL
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
21
MAINTAINERS
21
MAINTAINERS
@ -132,6 +132,7 @@ F: configs/targets/mips*
|
|||||||
|
|
||||||
X86 general architecture support
|
X86 general architecture support
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
|
R: Zhao Liu <zhao1.liu@intel.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: configs/devices/i386-softmmu/default.mak
|
F: configs/devices/i386-softmmu/default.mak
|
||||||
F: configs/targets/i386-softmmu.mak
|
F: configs/targets/i386-softmmu.mak
|
||||||
@ -1839,6 +1840,16 @@ F: hw/i386/microvm.c
|
|||||||
F: include/hw/i386/microvm.h
|
F: include/hw/i386/microvm.h
|
||||||
F: pc-bios/bios-microvm.bin
|
F: pc-bios/bios-microvm.bin
|
||||||
|
|
||||||
|
nitro-enclave
|
||||||
|
M: Alexander Graf <graf@amazon.com>
|
||||||
|
M: Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/core/eif.c
|
||||||
|
F: hw/core/eif.h
|
||||||
|
F: hw/i386/nitro_enclave.c
|
||||||
|
F: include/hw/i386/nitro_enclave.h
|
||||||
|
F: docs/system/i386/nitro-enclave.rst
|
||||||
|
|
||||||
Machine core
|
Machine core
|
||||||
M: Eduardo Habkost <eduardo@habkost.net>
|
M: Eduardo Habkost <eduardo@habkost.net>
|
||||||
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||||
@ -2298,6 +2309,16 @@ F: include/sysemu/rng*.h
|
|||||||
F: backends/rng*.c
|
F: backends/rng*.c
|
||||||
F: tests/qtest/virtio-rng-test.c
|
F: tests/qtest/virtio-rng-test.c
|
||||||
|
|
||||||
|
virtio-nsm
|
||||||
|
M: Alexander Graf <graf@amazon.com>
|
||||||
|
M: Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/virtio/cbor-helpers.c
|
||||||
|
F: hw/virtio/virtio-nsm.c
|
||||||
|
F: hw/virtio/virtio-nsm-pci.c
|
||||||
|
F: include/hw/virtio/cbor-helpers.h
|
||||||
|
F: include/hw/virtio/virtio-nsm.h
|
||||||
|
|
||||||
vhost-user-stubs
|
vhost-user-stubs
|
||||||
M: Alex Bennée <alex.bennee@linaro.org>
|
M: Alex Bennée <alex.bennee@linaro.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
@ -73,19 +73,17 @@ void accel_system_init_ops_interfaces(AccelClass *ac)
|
|||||||
g_assert(ac_name != NULL);
|
g_assert(ac_name != NULL);
|
||||||
|
|
||||||
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
||||||
ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name));
|
|
||||||
oc = module_object_class_by_name(ops_name);
|
oc = module_object_class_by_name(ops_name);
|
||||||
if (!oc) {
|
if (!oc) {
|
||||||
error_report("fatal: could not load module for type '%s'", ops_name);
|
error_report("fatal: could not load module for type '%s'", ops_name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
g_free(ops_name);
|
g_free(ops_name);
|
||||||
ops = ACCEL_OPS_CLASS(oc);
|
|
||||||
/*
|
/*
|
||||||
* all accelerators need to define ops, providing at least a mandatory
|
* all accelerators need to define ops, providing at least a mandatory
|
||||||
* non-NULL create_vcpu_thread operation.
|
* non-NULL create_vcpu_thread operation.
|
||||||
*/
|
*/
|
||||||
g_assert(ops != NULL);
|
ops = ACCEL_OPS_CLASS(oc);
|
||||||
if (ops->ops_init) {
|
if (ops->ops_init) {
|
||||||
ops->ops_init(ops);
|
ops->ops_init(ops);
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
|
|
||||||
|
|
||||||
OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendMemfd, MEMORY_BACKEND_MEMFD)
|
OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendMemfd, MEMORY_BACKEND_MEMFD)
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,3 +29,4 @@
|
|||||||
# CONFIG_I440FX=n
|
# CONFIG_I440FX=n
|
||||||
# CONFIG_Q35=n
|
# CONFIG_Q35=n
|
||||||
# CONFIG_MICROVM=n
|
# CONFIG_MICROVM=n
|
||||||
|
# CONFIG_NITRO_ENCLAVE=n
|
||||||
|
10
configure
vendored
10
configure
vendored
@ -395,7 +395,11 @@ elif check_define _ARCH_PPC ; then
|
|||||||
cpu="ppc"
|
cpu="ppc"
|
||||||
fi
|
fi
|
||||||
elif check_define __mips__ ; then
|
elif check_define __mips__ ; then
|
||||||
cpu="mips"
|
if check_define __mips64 ; then
|
||||||
|
cpu="mips64"
|
||||||
|
else
|
||||||
|
cpu="mips"
|
||||||
|
fi
|
||||||
elif check_define __s390__ ; then
|
elif check_define __s390__ ; then
|
||||||
if check_define __s390x__ ; then
|
if check_define __s390x__ ; then
|
||||||
cpu="s390x"
|
cpu="s390x"
|
||||||
@ -1230,7 +1234,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$host_arch" in
|
case "$cpu" in
|
||||||
arm)
|
arm)
|
||||||
# e.g. arm-unknown-linux-gnueabi, arm-unknown-linux-gnueabihf
|
# e.g. arm-unknown-linux-gnueabi, arm-unknown-linux-gnueabihf
|
||||||
write_c_skeleton
|
write_c_skeleton
|
||||||
@ -1278,7 +1282,7 @@ EOF
|
|||||||
test "$rust_arch" = arm && test "$rust_os" != linux && rust_arch=armv7
|
test "$rust_arch" = arm && test "$rust_os" != linux && rust_arch=armv7
|
||||||
;;
|
;;
|
||||||
|
|
||||||
mips|mips64)
|
mips)
|
||||||
# preserve ISA version (mipsisa64r6 etc.) and include endianness
|
# preserve ISA version (mipsisa64r6 etc.) and include endianness
|
||||||
rust_arch=${raw_cpu%el}
|
rust_arch=${raw_cpu%el}
|
||||||
test "$bigendian" = no && rust_arch=${rust_arch}el
|
test "$bigendian" = no && rust_arch=${rust_arch}el
|
||||||
|
@ -41,7 +41,7 @@ Those hosts are officially supported, with various accelerators:
|
|||||||
- Accelerators
|
- Accelerators
|
||||||
* - Arm
|
* - Arm
|
||||||
- kvm (64 bit only), tcg, xen
|
- kvm (64 bit only), tcg, xen
|
||||||
* - MIPS (little endian only)
|
* - MIPS (64 bit little endian only)
|
||||||
- kvm, tcg
|
- kvm, tcg
|
||||||
* - PPC
|
* - PPC
|
||||||
- kvm, tcg
|
- kvm, tcg
|
||||||
|
@ -164,15 +164,19 @@ property types.
|
|||||||
Host Architectures
|
Host Architectures
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
BE MIPS (since 7.2)
|
Big endian MIPS since 7.2; 32-bit little endian MIPS since 9.2
|
||||||
'''''''''''''''''''
|
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
As Debian 10 ("Buster") moved into LTS the big endian 32 bit version of
|
As Debian 10 ("Buster") moved into LTS the big endian 32 bit version of
|
||||||
MIPS moved out of support making it hard to maintain our
|
MIPS moved out of support making it hard to maintain our
|
||||||
cross-compilation CI tests of the architecture. As we no longer have
|
cross-compilation CI tests of the architecture. As we no longer have
|
||||||
CI coverage support may bitrot away before the deprecation process
|
CI coverage support may bitrot away before the deprecation process
|
||||||
completes. The little endian variants of MIPS (both 32 and 64 bit) are
|
completes.
|
||||||
still a supported host architecture.
|
|
||||||
|
Likewise, the little endian variant of 32 bit MIPS is not supported by
|
||||||
|
Debian 13 ("Trixie") and newer.
|
||||||
|
|
||||||
|
64 bit little endian MIPS is still a supported host architecture.
|
||||||
|
|
||||||
System emulation on 32-bit x86 hosts (since 8.0)
|
System emulation on 32-bit x86 hosts (since 8.0)
|
||||||
''''''''''''''''''''''''''''''''''''''''''''''''
|
''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
78
docs/system/i386/nitro-enclave.rst
Normal file
78
docs/system/i386/nitro-enclave.rst
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
'nitro-enclave' virtual machine (``nitro-enclave``)
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
``nitro-enclave`` is a machine type which emulates an *AWS nitro enclave*
|
||||||
|
virtual machine. `AWS nitro enclaves`_ is an Amazon EC2 feature that allows
|
||||||
|
creating isolated execution environments, called enclaves, from Amazon EC2
|
||||||
|
instances which are used for processing highly sensitive data. Enclaves have
|
||||||
|
no persistent storage and no external networking. The enclave VMs are based
|
||||||
|
on Firecracker microvm with a vhost-vsock device for communication with the
|
||||||
|
parent EC2 instance that spawned it and a Nitro Secure Module (NSM) device
|
||||||
|
for cryptographic attestation. The parent instance VM always has CID 3 while
|
||||||
|
the enclave VM gets a dynamic CID. Enclaves use an EIF (`Enclave Image Format`_)
|
||||||
|
file which contains the necessary kernel, cmdline and ramdisk(s) to boot.
|
||||||
|
|
||||||
|
In QEMU, ``nitro-enclave`` is a machine type based on ``microvm`` similar to how
|
||||||
|
AWS nitro enclaves are based on `Firecracker`_ microvm. This is useful for
|
||||||
|
local testing of EIF files using QEMU instead of running real AWS Nitro Enclaves
|
||||||
|
which can be difficult for debugging due to its roots in security. The vsock
|
||||||
|
device emulation is done using vhost-user-vsock which means another process that
|
||||||
|
can do the userspace emulation, like `vhost-device-vsock`_ from rust-vmm crate,
|
||||||
|
must be run alongside nitro-enclave for the vsock communication to work.
|
||||||
|
|
||||||
|
``libcbor`` and ``gnutls`` are required dependencies for nitro-enclave machine
|
||||||
|
support to be added when building QEMU from source.
|
||||||
|
|
||||||
|
.. _AWS nitro enclaves: https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave.html
|
||||||
|
.. _Enclave Image Format: https://github.com/aws/aws-nitro-enclaves-image-format
|
||||||
|
.. _vhost-device-vsock: https://github.com/rust-vmm/vhost-device/tree/main/vhost-device-vsock
|
||||||
|
.. _Firecracker: https://firecracker-microvm.github.io
|
||||||
|
|
||||||
|
Using the nitro-enclave machine type
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Machine-specific options
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
It supports the following machine-specific options:
|
||||||
|
|
||||||
|
- nitro-enclave.vsock=string (required) (Id of the chardev from '-chardev' option that vhost-user-vsock device will use)
|
||||||
|
- nitro-enclave.id=string (optional) (Set enclave identifier)
|
||||||
|
- nitro-enclave.parent-role=string (optional) (Set parent instance IAM role ARN)
|
||||||
|
- nitro-enclave.parent-id=string (optional) (Set parent instance identifier)
|
||||||
|
|
||||||
|
|
||||||
|
Running a nitro-enclave VM
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
First, run `vhost-device-vsock`__ (or a similar tool that supports vhost-user-vsock).
|
||||||
|
The forward-cid option below with value 1 forwards all connections from the enclave
|
||||||
|
VM to the host machine and the forward-listen (port numbers separated by '+') is used
|
||||||
|
for forwarding connections from the host machine to the enclave VM.
|
||||||
|
|
||||||
|
__ https://github.com/rust-vmm/vhost-device/tree/main/vhost-device-vsock#using-the-vsock-backend
|
||||||
|
|
||||||
|
$ vhost-device-vsock \
|
||||||
|
--vm guest-cid=4,forward-cid=1,forward-listen=9001+9002,socket=/tmp/vhost4.socket
|
||||||
|
|
||||||
|
Now run the necessary applications on the host machine so that the nitro-enclave VM
|
||||||
|
applications' vsock communication works. For example, the nitro-enclave VM's init
|
||||||
|
process connects to CID 3 and sends a single byte hello heartbeat (0xB7) to let the
|
||||||
|
parent VM know that it booted expecting a heartbeat (0xB7) response. So you must run
|
||||||
|
a AF_VSOCK server on the host machine that listens on port 9000 and sends the heartbeat
|
||||||
|
after it receives the heartbeat for enclave VM to boot successfully. You should run all
|
||||||
|
the applications on the host machine that would typically be running in the parent EC2
|
||||||
|
VM for successful communication with the enclave VM.
|
||||||
|
|
||||||
|
Then run the nitro-enclave VM using the following command where ``hello.eif`` is
|
||||||
|
an EIF file you would use to spawn a real AWS nitro enclave virtual machine:
|
||||||
|
|
||||||
|
$ qemu-system-x86_64 -M nitro-enclave,vsock=c,id=hello-world \
|
||||||
|
-kernel hello-world.eif -nographic -m 4G --enable-kvm -cpu host \
|
||||||
|
-chardev socket,id=c,path=/tmp/vhost4.socket
|
||||||
|
|
||||||
|
In this example, the nitro-enclave VM has CID 4. If there are applications that
|
||||||
|
connect to the enclave VM, run them on the host machine after enclave VM starts.
|
||||||
|
You need to modify the applications to connect to CID 1 (instead of the enclave
|
||||||
|
VM's CID) and use the forward-listen (e.g., 9001+9002) option of vhost-device-vsock
|
||||||
|
to forward the ports they connect to.
|
@ -14,8 +14,9 @@ Board-specific documentation
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
i386/microvm
|
|
||||||
i386/pc
|
i386/pc
|
||||||
|
i386/microvm
|
||||||
|
i386/nitro-enclave
|
||||||
|
|
||||||
Architectural features
|
Architectural features
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
/* Digested version of <cpuid.h> */
|
/* Digested version of <cpuid.h> */
|
||||||
|
|
||||||
#define CPUINFO_ALWAYS (1u << 0) /* so cpuinfo is nonzero */
|
#define CPUINFO_ALWAYS (1u << 0) /* so cpuinfo is nonzero */
|
||||||
|
#define CPUINFO_OSXSAVE (1u << 1)
|
||||||
#define CPUINFO_MOVBE (1u << 2)
|
#define CPUINFO_MOVBE (1u << 2)
|
||||||
#define CPUINFO_LZCNT (1u << 3)
|
#define CPUINFO_LZCNT (1u << 3)
|
||||||
#define CPUINFO_POPCNT (1u << 4)
|
#define CPUINFO_POPCNT (1u << 4)
|
||||||
|
@ -34,3 +34,7 @@ config REGISTER
|
|||||||
|
|
||||||
config SPLIT_IRQ
|
config SPLIT_IRQ
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config EIF
|
||||||
|
bool
|
||||||
|
depends on LIBCBOR && GNUTLS
|
||||||
|
719
hw/core/eif.c
Normal file
719
hw/core/eif.c
Normal file
@ -0,0 +1,719 @@
|
|||||||
|
/*
|
||||||
|
* EIF (Enclave Image Format) related helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/bswap.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "crypto/x509-utils.h"
|
||||||
|
#include <zlib.h> /* for crc32 */
|
||||||
|
#include <cbor.h>
|
||||||
|
|
||||||
|
#include "hw/core/eif.h"
|
||||||
|
|
||||||
|
#define MAX_SECTIONS 32
|
||||||
|
|
||||||
|
/* members are ordered according to field order in .eif file */
|
||||||
|
typedef struct EifHeader {
|
||||||
|
uint8_t magic[4]; /* must be .eif in ascii i.e., [46, 101, 105, 102] */
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t flags;
|
||||||
|
uint64_t default_memory;
|
||||||
|
uint64_t default_cpus;
|
||||||
|
uint16_t reserved;
|
||||||
|
uint16_t section_cnt;
|
||||||
|
uint64_t section_offsets[MAX_SECTIONS];
|
||||||
|
uint64_t section_sizes[MAX_SECTIONS];
|
||||||
|
uint32_t unused;
|
||||||
|
uint32_t eif_crc32;
|
||||||
|
} QEMU_PACKED EifHeader;
|
||||||
|
|
||||||
|
/* members are ordered according to field order in .eif file */
|
||||||
|
typedef struct EifSectionHeader {
|
||||||
|
/*
|
||||||
|
* 0 = invalid, 1 = kernel, 2 = cmdline, 3 = ramdisk, 4 = signature,
|
||||||
|
* 5 = metadata
|
||||||
|
*/
|
||||||
|
uint16_t section_type;
|
||||||
|
uint16_t flags;
|
||||||
|
uint64_t section_size;
|
||||||
|
} QEMU_PACKED EifSectionHeader;
|
||||||
|
|
||||||
|
enum EifSectionTypes {
|
||||||
|
EIF_SECTION_INVALID = 0,
|
||||||
|
EIF_SECTION_KERNEL = 1,
|
||||||
|
EIF_SECTION_CMDLINE = 2,
|
||||||
|
EIF_SECTION_RAMDISK = 3,
|
||||||
|
EIF_SECTION_SIGNATURE = 4,
|
||||||
|
EIF_SECTION_METADATA = 5,
|
||||||
|
EIF_SECTION_MAX = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *section_type_to_string(uint16_t type)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
switch (type) {
|
||||||
|
case EIF_SECTION_INVALID:
|
||||||
|
str = "invalid";
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_KERNEL:
|
||||||
|
str = "kernel";
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_CMDLINE:
|
||||||
|
str = "cmdline";
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_RAMDISK:
|
||||||
|
str = "ramdisk";
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_SIGNATURE:
|
||||||
|
str = "signature";
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_METADATA:
|
||||||
|
str = "metadata";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_eif_header(FILE *f, EifHeader *header, uint32_t *crc,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
size_t header_size = sizeof(*header);
|
||||||
|
|
||||||
|
got = fread(header, 1, header_size, f);
|
||||||
|
if (got != header_size) {
|
||||||
|
error_setg(errp, "Failed to read EIF header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(header->magic, ".eif", 4) != 0) {
|
||||||
|
error_setg(errp, "Invalid EIF image. Magic mismatch.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exclude header->eif_crc32 field from CRC calculation */
|
||||||
|
*crc = crc32(*crc, (uint8_t *)header, header_size - 4);
|
||||||
|
|
||||||
|
header->version = be16_to_cpu(header->version);
|
||||||
|
header->flags = be16_to_cpu(header->flags);
|
||||||
|
header->default_memory = be64_to_cpu(header->default_memory);
|
||||||
|
header->default_cpus = be64_to_cpu(header->default_cpus);
|
||||||
|
header->reserved = be16_to_cpu(header->reserved);
|
||||||
|
header->section_cnt = be16_to_cpu(header->section_cnt);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_SECTIONS; ++i) {
|
||||||
|
header->section_offsets[i] = be64_to_cpu(header->section_offsets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_SECTIONS; ++i) {
|
||||||
|
header->section_sizes[i] = be64_to_cpu(header->section_sizes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
header->unused = be32_to_cpu(header->unused);
|
||||||
|
header->eif_crc32 = be32_to_cpu(header->eif_crc32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_eif_section_header(FILE *f, EifSectionHeader *section_header,
|
||||||
|
uint32_t *crc, Error **errp)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
size_t section_header_size = sizeof(*section_header);
|
||||||
|
|
||||||
|
got = fread(section_header, 1, section_header_size, f);
|
||||||
|
if (got != section_header_size) {
|
||||||
|
error_setg(errp, "Failed to read EIF section header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*crc = crc32(*crc, (uint8_t *)section_header, section_header_size);
|
||||||
|
|
||||||
|
section_header->section_type = be16_to_cpu(section_header->section_type);
|
||||||
|
section_header->flags = be16_to_cpu(section_header->flags);
|
||||||
|
section_header->section_size = be64_to_cpu(section_header->section_size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Upon success, the caller is responsible for unlinking and freeing *tmp_path.
|
||||||
|
*/
|
||||||
|
static bool get_tmp_file(const char *template, char **tmp_path, Error **errp)
|
||||||
|
{
|
||||||
|
int tmp_fd;
|
||||||
|
|
||||||
|
*tmp_path = NULL;
|
||||||
|
tmp_fd = g_file_open_tmp(template, tmp_path, NULL);
|
||||||
|
if (tmp_fd < 0 || *tmp_path == NULL) {
|
||||||
|
error_setg(errp, "Failed to create temporary file for template %s",
|
||||||
|
template);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(tmp_fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void safe_fclose(FILE *f)
|
||||||
|
{
|
||||||
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void safe_unlink(char *f)
|
||||||
|
{
|
||||||
|
if (f) {
|
||||||
|
unlink(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Upon success, the caller is reponsible for unlinking and freeing *kernel_path
|
||||||
|
*/
|
||||||
|
static bool read_eif_kernel(FILE *f, uint64_t size, char **kernel_path,
|
||||||
|
uint8_t *kernel, uint32_t *crc, Error **errp)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
FILE *tmp_file = NULL;
|
||||||
|
|
||||||
|
*kernel_path = NULL;
|
||||||
|
if (!get_tmp_file("eif-kernel-XXXXXX", kernel_path, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_file = fopen(*kernel_path, "wb");
|
||||||
|
if (tmp_file == NULL) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to open temporary file %s",
|
||||||
|
*kernel_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = fread(kernel, 1, size, f);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to read EIF kernel section data");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = fwrite(kernel, 1, size, tmp_file);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to write EIF kernel section data to temporary"
|
||||||
|
" file");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
*crc = crc32(*crc, kernel, size);
|
||||||
|
fclose(tmp_file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
safe_fclose(tmp_file);
|
||||||
|
|
||||||
|
safe_unlink(*kernel_path);
|
||||||
|
g_free(*kernel_path);
|
||||||
|
*kernel_path = NULL;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_eif_cmdline(FILE *f, uint64_t size, char *cmdline,
|
||||||
|
uint32_t *crc, Error **errp)
|
||||||
|
{
|
||||||
|
size_t got = fread(cmdline, 1, size, f);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to read EIF cmdline section data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*crc = crc32(*crc, (uint8_t *)cmdline, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_eif_ramdisk(FILE *eif, FILE *initrd, uint64_t size,
|
||||||
|
uint8_t *ramdisk, uint32_t *crc, Error **errp)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
|
||||||
|
got = fread(ramdisk, 1, size, eif);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to read EIF ramdisk section data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = fwrite(ramdisk, 1, size, initrd);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to write EIF ramdisk data to temporary file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*crc = crc32(*crc, ramdisk, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_signature_fingerprint_sha384(FILE *eif, uint64_t size,
|
||||||
|
uint8_t *sha384,
|
||||||
|
uint32_t *crc,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
g_autofree uint8_t *sig = NULL;
|
||||||
|
g_autofree uint8_t *cert = NULL;
|
||||||
|
cbor_item_t *item = NULL;
|
||||||
|
cbor_item_t *pcr0 = NULL;
|
||||||
|
size_t len;
|
||||||
|
size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
|
||||||
|
struct cbor_pair *pair;
|
||||||
|
struct cbor_load_result result;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
sig = g_malloc(size);
|
||||||
|
got = fread(sig, 1, size, eif);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
error_setg(errp, "Failed to read EIF signature section data");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
*crc = crc32(*crc, sig, size);
|
||||||
|
|
||||||
|
item = cbor_load(sig, size, &result);
|
||||||
|
if (!item || result.error.code != CBOR_ERR_NONE) {
|
||||||
|
error_setg(errp, "Failed to load signature section data as CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!cbor_isa_array(item) || cbor_array_size(item) < 1) {
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
pcr0 = cbor_array_get(item, 0);
|
||||||
|
if (!pcr0) {
|
||||||
|
error_setg(errp, "Failed to get PCR0 signature");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!cbor_isa_map(pcr0) || cbor_map_size(pcr0) != 2) {
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
pair = cbor_map_handle(pcr0);
|
||||||
|
if (!cbor_isa_string(pair->key) || cbor_string_length(pair->key) != 19 ||
|
||||||
|
memcmp(cbor_string_handle(pair->key), "signing_certificate", 19) != 0) {
|
||||||
|
error_setg(errp, "Invalid signautre CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!cbor_isa_array(pair->value)) {
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
len = cbor_array_size(pair->value);
|
||||||
|
if (len == 0) {
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
cert = g_malloc(len);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
cbor_item_t *tmp = cbor_array_get(pair->value, i);
|
||||||
|
if (!tmp) {
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!cbor_isa_uint(tmp) || cbor_int_get_width(tmp) != CBOR_INT_8) {
|
||||||
|
cbor_decref(&tmp);
|
||||||
|
error_setg(errp, "Invalid signature CBOR");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
cert[i] = cbor_get_uint8(tmp);
|
||||||
|
cbor_decref(&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qcrypto_get_x509_cert_fingerprint(cert, len, QCRYPTO_HASH_ALGO_SHA384,
|
||||||
|
sha384, &hash_len, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pcr0) {
|
||||||
|
cbor_decref(&pcr0);
|
||||||
|
}
|
||||||
|
if (item) {
|
||||||
|
cbor_decref(&item);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expects file to have offset 0 before this function is called */
|
||||||
|
static long get_file_size(FILE *f, Error **errp)
|
||||||
|
{
|
||||||
|
long size;
|
||||||
|
|
||||||
|
if (fseek(f, 0, SEEK_END) != 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to seek to the end of file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = ftell(f);
|
||||||
|
if (size == -1) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to get offset");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to seek back to the start");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_SHA384_digest(GList *list, uint8_t *digest, Error **errp)
|
||||||
|
{
|
||||||
|
size_t digest_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
|
||||||
|
size_t list_len = g_list_length(list);
|
||||||
|
struct iovec *iovec_list = g_new0(struct iovec, list_len);
|
||||||
|
bool ret = true;
|
||||||
|
GList *l;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0, l = list; l != NULL; l = l->next, i++) {
|
||||||
|
iovec_list[i] = *(struct iovec *) l->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA384, iovec_list, list_len,
|
||||||
|
&digest, &digest_len, errp) < 0) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(iovec_list);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_iovec(struct iovec *iov)
|
||||||
|
{
|
||||||
|
if (iov) {
|
||||||
|
g_free(iov->iov_base);
|
||||||
|
g_free(iov);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Upon success, the caller is reponsible for unlinking and freeing
|
||||||
|
* *kernel_path, *initrd_path and freeing *cmdline.
|
||||||
|
*/
|
||||||
|
bool read_eif_file(const char *eif_path, const char *machine_initrd,
|
||||||
|
char **kernel_path, char **initrd_path, char **cmdline,
|
||||||
|
uint8_t *image_sha384, uint8_t *bootstrap_sha384,
|
||||||
|
uint8_t *app_sha384, uint8_t *fingerprint_sha384,
|
||||||
|
bool *signature_found, Error **errp)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
FILE *machine_initrd_f = NULL;
|
||||||
|
FILE *initrd_path_f = NULL;
|
||||||
|
long machine_initrd_size;
|
||||||
|
uint32_t crc = 0;
|
||||||
|
EifHeader eif_header;
|
||||||
|
bool seen_sections[EIF_SECTION_MAX] = {false};
|
||||||
|
/* kernel + ramdisks + cmdline sha384 hash */
|
||||||
|
GList *iov_PCR0 = NULL;
|
||||||
|
/* kernel + boot ramdisk + cmdline sha384 hash */
|
||||||
|
GList *iov_PCR1 = NULL;
|
||||||
|
/* application ramdisk(s) hash */
|
||||||
|
GList *iov_PCR2 = NULL;
|
||||||
|
uint8_t *ptr = NULL;
|
||||||
|
struct iovec *iov_ptr = NULL;
|
||||||
|
|
||||||
|
*signature_found = false;
|
||||||
|
*kernel_path = *initrd_path = *cmdline = NULL;
|
||||||
|
|
||||||
|
f = fopen(eif_path, "rb");
|
||||||
|
if (f == NULL) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to open %s", eif_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_eif_header(f, &eif_header, &crc, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eif_header.version < 4) {
|
||||||
|
error_setg(errp, "Expected EIF version 4 or greater");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eif_header.flags != 0) {
|
||||||
|
error_setg(errp, "Expected EIF flags to be 0");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eif_header.section_cnt > MAX_SECTIONS) {
|
||||||
|
error_setg(errp, "EIF header section count must not be greater than "
|
||||||
|
"%d but found %d", MAX_SECTIONS, eif_header.section_cnt);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < eif_header.section_cnt; ++i) {
|
||||||
|
EifSectionHeader hdr;
|
||||||
|
uint16_t section_type;
|
||||||
|
|
||||||
|
if (fseek(f, eif_header.section_offsets[i], SEEK_SET) != 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to offset to %" PRIu64 " in EIF file",
|
||||||
|
eif_header.section_offsets[i]);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_eif_section_header(f, &hdr, &crc, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.flags != 0) {
|
||||||
|
error_setg(errp, "Expected EIF section header flags to be 0");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eif_header.section_sizes[i] != hdr.section_size) {
|
||||||
|
error_setg(errp, "EIF section size mismatch between header and "
|
||||||
|
"section header: header %" PRIu64 ", section header %" PRIu64,
|
||||||
|
eif_header.section_sizes[i],
|
||||||
|
hdr.section_size);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
section_type = hdr.section_type;
|
||||||
|
|
||||||
|
switch (section_type) {
|
||||||
|
case EIF_SECTION_KERNEL:
|
||||||
|
if (seen_sections[EIF_SECTION_KERNEL]) {
|
||||||
|
error_setg(errp, "Invalid EIF image. More than 1 kernel "
|
||||||
|
"section");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = g_malloc(hdr.section_size);
|
||||||
|
|
||||||
|
iov_ptr = g_malloc(sizeof(struct iovec));
|
||||||
|
iov_ptr->iov_base = ptr;
|
||||||
|
iov_ptr->iov_len = hdr.section_size;
|
||||||
|
|
||||||
|
iov_PCR0 = g_list_append(iov_PCR0, iov_ptr);
|
||||||
|
iov_PCR1 = g_list_append(iov_PCR1, iov_ptr);
|
||||||
|
|
||||||
|
if (!read_eif_kernel(f, hdr.section_size, kernel_path, ptr, &crc,
|
||||||
|
errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case EIF_SECTION_CMDLINE:
|
||||||
|
{
|
||||||
|
uint64_t size;
|
||||||
|
uint8_t *cmdline_copy;
|
||||||
|
if (seen_sections[EIF_SECTION_CMDLINE]) {
|
||||||
|
error_setg(errp, "Invalid EIF image. More than 1 cmdline "
|
||||||
|
"section");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
size = hdr.section_size;
|
||||||
|
*cmdline = g_malloc(size + 1);
|
||||||
|
if (!read_eif_cmdline(f, size, *cmdline, &crc, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
(*cmdline)[size] = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We make a copy of '*cmdline' for putting it in iovecs so that
|
||||||
|
* we can easily free all the iovec entries later as we cannot
|
||||||
|
* free '*cmdline' which is used by the caller.
|
||||||
|
*/
|
||||||
|
cmdline_copy = g_memdup2(*cmdline, size);
|
||||||
|
|
||||||
|
iov_ptr = g_malloc(sizeof(struct iovec));
|
||||||
|
iov_ptr->iov_base = cmdline_copy;
|
||||||
|
iov_ptr->iov_len = size;
|
||||||
|
|
||||||
|
iov_PCR0 = g_list_append(iov_PCR0, iov_ptr);
|
||||||
|
iov_PCR1 = g_list_append(iov_PCR1, iov_ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EIF_SECTION_RAMDISK:
|
||||||
|
{
|
||||||
|
if (!seen_sections[EIF_SECTION_RAMDISK]) {
|
||||||
|
/*
|
||||||
|
* If this is the first time we are seeing a ramdisk section,
|
||||||
|
* we need to create the initrd temporary file.
|
||||||
|
*/
|
||||||
|
if (!get_tmp_file("eif-initrd-XXXXXX", initrd_path, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
initrd_path_f = fopen(*initrd_path, "wb");
|
||||||
|
if (initrd_path_f == NULL) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to open file %s",
|
||||||
|
*initrd_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = g_malloc(hdr.section_size);
|
||||||
|
|
||||||
|
iov_ptr = g_malloc(sizeof(struct iovec));
|
||||||
|
iov_ptr->iov_base = ptr;
|
||||||
|
iov_ptr->iov_len = hdr.section_size;
|
||||||
|
|
||||||
|
iov_PCR0 = g_list_append(iov_PCR0, iov_ptr);
|
||||||
|
/*
|
||||||
|
* If it's the first ramdisk, we need to hash it into bootstrap
|
||||||
|
* i.e., iov_PCR1, otherwise we need to hash it into app i.e.,
|
||||||
|
* iov_PCR2.
|
||||||
|
*/
|
||||||
|
if (!seen_sections[EIF_SECTION_RAMDISK]) {
|
||||||
|
iov_PCR1 = g_list_append(iov_PCR1, iov_ptr);
|
||||||
|
} else {
|
||||||
|
iov_PCR2 = g_list_append(iov_PCR2, iov_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_eif_ramdisk(f, initrd_path_f, hdr.section_size, ptr,
|
||||||
|
&crc, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EIF_SECTION_SIGNATURE:
|
||||||
|
*signature_found = true;
|
||||||
|
if (!get_signature_fingerprint_sha384(f, hdr.section_size,
|
||||||
|
fingerprint_sha384, &crc,
|
||||||
|
errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* other sections including invalid or unknown sections */
|
||||||
|
{
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t got;
|
||||||
|
uint64_t size = hdr.section_size;
|
||||||
|
buf = g_malloc(size);
|
||||||
|
got = fread(buf, 1, size, f);
|
||||||
|
if ((uint64_t) got != size) {
|
||||||
|
g_free(buf);
|
||||||
|
error_setg(errp, "Failed to read EIF %s section data",
|
||||||
|
section_type_to_string(section_type));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
crc = crc32(crc, buf, size);
|
||||||
|
g_free(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section_type < EIF_SECTION_MAX) {
|
||||||
|
seen_sections[section_type] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seen_sections[EIF_SECTION_KERNEL]) {
|
||||||
|
error_setg(errp, "Invalid EIF image. No kernel section.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!seen_sections[EIF_SECTION_CMDLINE]) {
|
||||||
|
error_setg(errp, "Invalid EIF image. No cmdline section.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!seen_sections[EIF_SECTION_RAMDISK]) {
|
||||||
|
error_setg(errp, "Invalid EIF image. No ramdisk section.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eif_header.eif_crc32 != crc) {
|
||||||
|
error_setg(errp, "CRC mismatch. Expected %u but header has %u.",
|
||||||
|
crc, eif_header.eif_crc32);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Let's append the initrd file from "-initrd" option if any. Although
|
||||||
|
* we pass the crc pointer to read_eif_ramdisk, it is not useful anymore.
|
||||||
|
* We have already done the crc mismatch check above this code.
|
||||||
|
*/
|
||||||
|
if (machine_initrd) {
|
||||||
|
machine_initrd_f = fopen(machine_initrd, "rb");
|
||||||
|
if (machine_initrd_f == NULL) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to open initrd file %s",
|
||||||
|
machine_initrd);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_initrd_size = get_file_size(machine_initrd_f, errp);
|
||||||
|
if (machine_initrd_size == -1) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = g_malloc(machine_initrd_size);
|
||||||
|
|
||||||
|
iov_ptr = g_malloc(sizeof(struct iovec));
|
||||||
|
iov_ptr->iov_base = ptr;
|
||||||
|
iov_ptr->iov_len = machine_initrd_size;
|
||||||
|
|
||||||
|
iov_PCR0 = g_list_append(iov_PCR0, iov_ptr);
|
||||||
|
iov_PCR2 = g_list_append(iov_PCR2, iov_ptr);
|
||||||
|
|
||||||
|
if (!read_eif_ramdisk(machine_initrd_f, initrd_path_f,
|
||||||
|
machine_initrd_size, ptr, &crc, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!get_SHA384_digest(iov_PCR0, image_sha384, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!get_SHA384_digest(iov_PCR1, bootstrap_sha384, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!get_SHA384_digest(iov_PCR2, app_sha384, errp)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only need to free iov_PCR0 entries because iov_PCR1 and
|
||||||
|
* iov_PCR2 iovec entries are subsets of iov_PCR0 iovec entries.
|
||||||
|
*/
|
||||||
|
g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec);
|
||||||
|
g_list_free(iov_PCR1);
|
||||||
|
g_list_free(iov_PCR2);
|
||||||
|
fclose(f);
|
||||||
|
fclose(initrd_path_f);
|
||||||
|
safe_fclose(machine_initrd_f);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec);
|
||||||
|
g_list_free(iov_PCR1);
|
||||||
|
g_list_free(iov_PCR2);
|
||||||
|
|
||||||
|
safe_fclose(f);
|
||||||
|
safe_fclose(initrd_path_f);
|
||||||
|
safe_fclose(machine_initrd_f);
|
||||||
|
|
||||||
|
safe_unlink(*kernel_path);
|
||||||
|
g_free(*kernel_path);
|
||||||
|
*kernel_path = NULL;
|
||||||
|
|
||||||
|
safe_unlink(*initrd_path);
|
||||||
|
g_free(*initrd_path);
|
||||||
|
*initrd_path = NULL;
|
||||||
|
|
||||||
|
g_free(*cmdline);
|
||||||
|
*cmdline = NULL;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
22
hw/core/eif.h
Normal file
22
hw/core/eif.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* EIF (Enclave Image Format) related helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_CORE_EIF_H
|
||||||
|
#define HW_CORE_EIF_H
|
||||||
|
|
||||||
|
bool read_eif_file(const char *eif_path, const char *machine_initrd,
|
||||||
|
char **kernel_path, char **initrd_path,
|
||||||
|
char **kernel_cmdline, uint8_t *image_sha384,
|
||||||
|
uint8_t *bootstrap_sha384, uint8_t *app_sha384,
|
||||||
|
uint8_t *fingerprint_sha384, bool *signature_found,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1001,6 +1001,39 @@ void machine_add_audiodev_property(MachineClass *mc)
|
|||||||
"Audiodev to use for default machine devices");
|
"Audiodev to use for default machine devices");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool create_default_memdev(MachineState *ms, const char *path,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
Object *obj;
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
bool r = false;
|
||||||
|
|
||||||
|
obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
|
||||||
|
if (path) {
|
||||||
|
if (!object_property_set_str(obj, "mem-path", path, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
object_property_add_child(object_get_objects_root(), mc->default_ram_id,
|
||||||
|
obj);
|
||||||
|
/* Ensure backend's memory region name is equal to mc->default_ram_id */
|
||||||
|
if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
|
||||||
|
false, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
object_unref(obj);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static void machine_class_init(ObjectClass *oc, void *data)
|
static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
@ -1020,6 +1053,8 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
|||||||
*/
|
*/
|
||||||
mc->numa_mem_align_shift = 23;
|
mc->numa_mem_align_shift = 23;
|
||||||
|
|
||||||
|
mc->create_default_memdev = create_default_memdev;
|
||||||
|
|
||||||
object_class_property_add_str(oc, "kernel",
|
object_class_property_add_str(oc, "kernel",
|
||||||
machine_get_kernel, machine_set_kernel);
|
machine_get_kernel, machine_set_kernel);
|
||||||
object_class_property_set_description(oc, "kernel",
|
object_class_property_set_description(oc, "kernel",
|
||||||
@ -1413,38 +1448,6 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool create_default_memdev(MachineState *ms, const char *path, Error **errp)
|
|
||||||
{
|
|
||||||
Object *obj;
|
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
||||||
bool r = false;
|
|
||||||
|
|
||||||
obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
|
|
||||||
if (path) {
|
|
||||||
if (!object_property_set_str(obj, "mem-path", path, errp)) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
object_property_add_child(object_get_objects_root(), mc->default_ram_id,
|
|
||||||
obj);
|
|
||||||
/* Ensure backend's memory region name is equal to mc->default_ram_id */
|
|
||||||
if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
|
|
||||||
false, errp)) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
|
|
||||||
|
|
||||||
out:
|
|
||||||
object_unref(obj);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *machine_class_default_cpu_type(MachineClass *mc)
|
const char *machine_class_default_cpu_type(MachineClass *mc)
|
||||||
{
|
{
|
||||||
if (mc->valid_cpu_types && !mc->valid_cpu_types[1]) {
|
if (mc->valid_cpu_types && !mc->valid_cpu_types[1]) {
|
||||||
@ -1548,7 +1551,9 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
|
|||||||
machine_class->default_ram_id);
|
machine_class->default_ram_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!create_default_memdev(current_machine, mem_path, errp)) {
|
|
||||||
|
if (!machine_class->create_default_memdev(current_machine, mem_path,
|
||||||
|
errp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ system_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c'))
|
|||||||
system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c'))
|
system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c'))
|
||||||
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c'))
|
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c'))
|
||||||
system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c'))
|
system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c'))
|
||||||
|
system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls])
|
||||||
|
|
||||||
system_ss.add(files(
|
system_ss.add(files(
|
||||||
'cpu-sysemu.c',
|
'cpu-sysemu.c',
|
||||||
|
@ -146,31 +146,16 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
|
|||||||
|
|
||||||
DeviceState *qdev_new(const char *name)
|
DeviceState *qdev_new(const char *name)
|
||||||
{
|
{
|
||||||
ObjectClass *oc = object_class_by_name(name);
|
|
||||||
#ifdef CONFIG_MODULES
|
|
||||||
if (!oc) {
|
|
||||||
int rv = module_load_qom(name, &error_fatal);
|
|
||||||
if (rv > 0) {
|
|
||||||
oc = object_class_by_name(name);
|
|
||||||
} else {
|
|
||||||
error_report("could not find a module for type '%s'", name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!oc) {
|
|
||||||
error_report("unknown type '%s'", name);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
return DEVICE(object_new(name));
|
return DEVICE(object_new(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceState *qdev_try_new(const char *name)
|
DeviceState *qdev_try_new(const char *name)
|
||||||
{
|
{
|
||||||
if (!module_object_class_by_name(name)) {
|
ObjectClass *oc = module_object_class_by_name(name);
|
||||||
|
if (!oc) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return DEVICE(object_new(name));
|
return DEVICE(object_new_with_class(oc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static QTAILQ_HEAD(, DeviceListener) device_listeners
|
static QTAILQ_HEAD(, DeviceListener) device_listeners
|
||||||
|
@ -129,6 +129,16 @@ config MICROVM
|
|||||||
select USB_XHCI_SYSBUS
|
select USB_XHCI_SYSBUS
|
||||||
select I8254
|
select I8254
|
||||||
|
|
||||||
|
config NITRO_ENCLAVE
|
||||||
|
default y
|
||||||
|
depends on I386 && FDT # for MICROVM
|
||||||
|
depends on LIBCBOR && GNUTLS # for EIF and VIRTIO_NSM
|
||||||
|
depends on VHOST_USER # for VHOST_USER_VSOCK
|
||||||
|
select EIF
|
||||||
|
select MICROVM
|
||||||
|
select VHOST_USER_VSOCK
|
||||||
|
select VIRTIO_NSM
|
||||||
|
|
||||||
config X86_IOMMU
|
config X86_IOMMU
|
||||||
bool
|
bool
|
||||||
depends on PC
|
depends on PC
|
||||||
|
@ -15,6 +15,7 @@ i386_ss.add(when: 'CONFIG_AMD_IOMMU', if_true: files('amd_iommu.c'),
|
|||||||
if_false: files('amd_iommu-stub.c'))
|
if_false: files('amd_iommu-stub.c'))
|
||||||
i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c'))
|
i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c'))
|
||||||
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('x86-common.c', 'microvm.c', 'acpi-microvm.c', 'microvm-dt.c'))
|
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('x86-common.c', 'microvm.c', 'acpi-microvm.c', 'microvm-dt.c'))
|
||||||
|
i386_ss.add(when: 'CONFIG_NITRO_ENCLAVE', if_true: files('nitro_enclave.c'))
|
||||||
i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
|
i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
|
||||||
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
|
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
|
||||||
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
|
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
|
||||||
|
@ -283,6 +283,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
|
|||||||
|
|
||||||
static void microvm_memory_init(MicrovmMachineState *mms)
|
static void microvm_memory_init(MicrovmMachineState *mms)
|
||||||
{
|
{
|
||||||
|
MicrovmMachineClass *mmc = MICROVM_MACHINE_GET_CLASS(mms);
|
||||||
MachineState *machine = MACHINE(mms);
|
MachineState *machine = MACHINE(mms);
|
||||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||||
MemoryRegion *ram_below_4g, *ram_above_4g;
|
MemoryRegion *ram_below_4g, *ram_above_4g;
|
||||||
@ -328,7 +329,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
|
|||||||
rom_set_fw(fw_cfg);
|
rom_set_fw(fw_cfg);
|
||||||
|
|
||||||
if (machine->kernel_filename != NULL) {
|
if (machine->kernel_filename != NULL) {
|
||||||
x86_load_linux(x86ms, fw_cfg, 0, true);
|
mmc->x86_load_linux(x86ms, fw_cfg, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mms->option_roms) {
|
if (mms->option_roms) {
|
||||||
@ -637,9 +638,12 @@ GlobalProperty microvm_properties[] = {
|
|||||||
static void microvm_class_init(ObjectClass *oc, void *data)
|
static void microvm_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
|
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
|
||||||
|
MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||||
|
|
||||||
|
mmc->x86_load_linux = x86_load_linux;
|
||||||
|
|
||||||
mc->init = microvm_machine_state_init;
|
mc->init = microvm_machine_state_init;
|
||||||
|
|
||||||
mc->family = "microvm_i386";
|
mc->family = "microvm_i386";
|
||||||
|
354
hw/i386/nitro_enclave.c
Normal file
354
hw/i386/nitro_enclave.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* AWS nitro-enclave machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qom/object_interfaces.h"
|
||||||
|
|
||||||
|
#include "chardev/char.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/core/eif.h"
|
||||||
|
#include "hw/i386/x86.h"
|
||||||
|
#include "hw/i386/microvm.h"
|
||||||
|
#include "hw/i386/nitro_enclave.h"
|
||||||
|
#include "hw/virtio/virtio-mmio.h"
|
||||||
|
#include "hw/virtio/virtio-nsm.h"
|
||||||
|
#include "hw/virtio/vhost-user-vsock.h"
|
||||||
|
#include "sysemu/hostmem.h"
|
||||||
|
|
||||||
|
static BusState *find_free_virtio_mmio_bus(void)
|
||||||
|
{
|
||||||
|
BusChild *kid;
|
||||||
|
BusState *bus = sysbus_get_default();
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||||
|
DeviceState *dev = kid->child;
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO)) {
|
||||||
|
VirtIOMMIOProxy *mmio = VIRTIO_MMIO(OBJECT(dev));
|
||||||
|
VirtioBusState *mmio_virtio_bus = &mmio->bus;
|
||||||
|
BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
|
||||||
|
if (QTAILQ_EMPTY(&mmio_bus->children)) {
|
||||||
|
return mmio_bus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vhost_user_vsock_init(NitroEnclaveMachineState *nems)
|
||||||
|
{
|
||||||
|
DeviceState *dev = qdev_new(TYPE_VHOST_USER_VSOCK);
|
||||||
|
VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
|
||||||
|
BusState *bus;
|
||||||
|
|
||||||
|
if (!nems->vsock) {
|
||||||
|
error_report("A valid chardev id for vhost-user-vsock device must be "
|
||||||
|
"provided using the 'vsock' machine option");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = find_free_virtio_mmio_bus();
|
||||||
|
if (!bus) {
|
||||||
|
error_report("Failed to find bus for vhost-user-vsock device");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chardev *chardev = qemu_chr_find(nems->vsock);
|
||||||
|
if (!chardev) {
|
||||||
|
error_report("Failed to find chardev with id %s", nems->vsock);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vsock->conf.chardev.chr = chardev;
|
||||||
|
|
||||||
|
qdev_realize_and_unref(dev, bus, &error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_nsm_init(NitroEnclaveMachineState *nems)
|
||||||
|
{
|
||||||
|
DeviceState *dev = qdev_new(TYPE_VIRTIO_NSM);
|
||||||
|
VirtIONSM *vnsm = VIRTIO_NSM(dev);
|
||||||
|
BusState *bus = find_free_virtio_mmio_bus();
|
||||||
|
|
||||||
|
if (!bus) {
|
||||||
|
error_report("Failed to find bus for virtio-nsm device.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
qdev_prop_set_string(dev, "module-id", nems->id);
|
||||||
|
|
||||||
|
qdev_realize_and_unref(dev, bus, &error_fatal);
|
||||||
|
nems->vnsm = vnsm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_devices_init(NitroEnclaveMachineState *nems)
|
||||||
|
{
|
||||||
|
vhost_user_vsock_init(nems);
|
||||||
|
virtio_nsm_init(nems);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_machine_state_init(MachineState *machine)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineClass *ne_class =
|
||||||
|
NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
|
||||||
|
NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
|
||||||
|
|
||||||
|
ne_class->parent_init(machine);
|
||||||
|
nitro_enclave_devices_init(ne_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_machine_reset(MachineState *machine, ResetType type)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineClass *ne_class =
|
||||||
|
NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
|
||||||
|
NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
|
||||||
|
|
||||||
|
ne_class->parent_reset(machine, type);
|
||||||
|
|
||||||
|
memset(ne_state->vnsm->pcrs, 0, sizeof(ne_state->vnsm->pcrs));
|
||||||
|
|
||||||
|
/* PCR0 */
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 0, ne_state->image_sha384,
|
||||||
|
QCRYPTO_HASH_DIGEST_LEN_SHA384);
|
||||||
|
/* PCR1 */
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 1, ne_state->bootstrap_sha384,
|
||||||
|
QCRYPTO_HASH_DIGEST_LEN_SHA384);
|
||||||
|
/* PCR2 */
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 2, ne_state->app_sha384,
|
||||||
|
QCRYPTO_HASH_DIGEST_LEN_SHA384);
|
||||||
|
/* PCR3 */
|
||||||
|
if (ne_state->parent_role) {
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 3,
|
||||||
|
(uint8_t *) ne_state->parent_role,
|
||||||
|
strlen(ne_state->parent_role));
|
||||||
|
}
|
||||||
|
/* PCR4 */
|
||||||
|
if (ne_state->parent_id) {
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 4,
|
||||||
|
(uint8_t *) ne_state->parent_id,
|
||||||
|
strlen(ne_state->parent_id));
|
||||||
|
}
|
||||||
|
/* PCR8 */
|
||||||
|
if (ne_state->signature_found) {
|
||||||
|
ne_state->vnsm->extend_pcr(ne_state->vnsm, 8,
|
||||||
|
ne_state->fingerprint_sha384,
|
||||||
|
QCRYPTO_HASH_DIGEST_LEN_SHA384);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First 16 PCRs are locked from boot and reserved for nitro enclave */
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
ne_state->vnsm->lock_pcr(ne_state->vnsm, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_machine_initfn(Object *obj)
|
||||||
|
{
|
||||||
|
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
|
||||||
|
X86MachineState *x86ms = X86_MACHINE(obj);
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
nems->id = g_strdup("i-234-enc5678");
|
||||||
|
|
||||||
|
/* AWS nitro enclaves have PCIE and ACPI disabled */
|
||||||
|
mms->pcie = ON_OFF_AUTO_OFF;
|
||||||
|
x86ms->acpi = ON_OFF_AUTO_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void x86_load_eif(X86MachineState *x86ms, FWCfgState *fw_cfg,
|
||||||
|
int acpi_data_size, bool pvh_enabled)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
char *eif_kernel, *eif_initrd, *eif_cmdline;
|
||||||
|
MachineState *machine = MACHINE(x86ms);
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(x86ms);
|
||||||
|
|
||||||
|
if (!read_eif_file(machine->kernel_filename, machine->initrd_filename,
|
||||||
|
&eif_kernel, &eif_initrd, &eif_cmdline,
|
||||||
|
nems->image_sha384, nems->bootstrap_sha384,
|
||||||
|
nems->app_sha384, nems->fingerprint_sha384,
|
||||||
|
&(nems->signature_found), &err)) {
|
||||||
|
error_report_err(err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(machine->kernel_filename);
|
||||||
|
machine->kernel_filename = eif_kernel;
|
||||||
|
g_free(machine->initrd_filename);
|
||||||
|
machine->initrd_filename = eif_initrd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If kernel cmdline argument was provided, let's concatenate it to the
|
||||||
|
* extracted EIF kernel cmdline.
|
||||||
|
*/
|
||||||
|
if (machine->kernel_cmdline != NULL) {
|
||||||
|
char *cmd = g_strdup_printf("%s %s", eif_cmdline,
|
||||||
|
machine->kernel_cmdline);
|
||||||
|
g_free(eif_cmdline);
|
||||||
|
g_free(machine->kernel_cmdline);
|
||||||
|
machine->kernel_cmdline = cmd;
|
||||||
|
} else {
|
||||||
|
machine->kernel_cmdline = eif_cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_load_linux(x86ms, fw_cfg, 0, true);
|
||||||
|
|
||||||
|
unlink(machine->kernel_filename);
|
||||||
|
unlink(machine->initrd_filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool create_memfd_backend(MachineState *ms, const char *path,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
Object *obj;
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
bool r = false;
|
||||||
|
|
||||||
|
obj = object_new(TYPE_MEMORY_BACKEND_MEMFD);
|
||||||
|
if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
object_property_add_child(object_get_objects_root(), mc->default_ram_id,
|
||||||
|
obj);
|
||||||
|
|
||||||
|
if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
object_unref(obj);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *nitro_enclave_get_vsock_chardev_id(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
return g_strdup(nems->vsock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_set_vsock_chardev_id(Object *obj, const char *value,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(nems->vsock);
|
||||||
|
nems->vsock = g_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *nitro_enclave_get_id(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
return g_strdup(nems->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_set_id(Object *obj, const char *value,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(nems->id);
|
||||||
|
nems->id = g_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *nitro_enclave_get_parent_role(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
return g_strdup(nems->parent_role);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_set_parent_role(Object *obj, const char *value,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(nems->parent_role);
|
||||||
|
nems->parent_role = g_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *nitro_enclave_get_parent_id(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
return g_strdup(nems->parent_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_set_parent_id(Object *obj, const char *value,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(nems->parent_id);
|
||||||
|
nems->parent_id = g_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nitro_enclave_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
|
||||||
|
NitroEnclaveMachineClass *nemc = NITRO_ENCLAVE_MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mmc->x86_load_linux = x86_load_eif;
|
||||||
|
|
||||||
|
mc->family = "nitro_enclave_i386";
|
||||||
|
mc->desc = "AWS Nitro Enclave";
|
||||||
|
|
||||||
|
nemc->parent_init = mc->init;
|
||||||
|
mc->init = nitro_enclave_machine_state_init;
|
||||||
|
|
||||||
|
nemc->parent_reset = mc->reset;
|
||||||
|
mc->reset = nitro_enclave_machine_reset;
|
||||||
|
|
||||||
|
mc->create_default_memdev = create_memfd_backend;
|
||||||
|
|
||||||
|
object_class_property_add_str(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
|
||||||
|
nitro_enclave_get_vsock_chardev_id,
|
||||||
|
nitro_enclave_set_vsock_chardev_id);
|
||||||
|
object_class_property_set_description(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
|
||||||
|
"Set chardev id for vhost-user-vsock "
|
||||||
|
"device");
|
||||||
|
|
||||||
|
object_class_property_add_str(oc, NITRO_ENCLAVE_ID, nitro_enclave_get_id,
|
||||||
|
nitro_enclave_set_id);
|
||||||
|
object_class_property_set_description(oc, NITRO_ENCLAVE_ID,
|
||||||
|
"Set enclave identifier");
|
||||||
|
|
||||||
|
object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ROLE,
|
||||||
|
nitro_enclave_get_parent_role,
|
||||||
|
nitro_enclave_set_parent_role);
|
||||||
|
object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ROLE,
|
||||||
|
"Set parent instance IAM role ARN");
|
||||||
|
|
||||||
|
object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ID,
|
||||||
|
nitro_enclave_get_parent_id,
|
||||||
|
nitro_enclave_set_parent_id);
|
||||||
|
object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ID,
|
||||||
|
"Set parent instance identifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo nitro_enclave_machine_info = {
|
||||||
|
.name = TYPE_NITRO_ENCLAVE_MACHINE,
|
||||||
|
.parent = TYPE_MICROVM_MACHINE,
|
||||||
|
.instance_size = sizeof(NitroEnclaveMachineState),
|
||||||
|
.instance_init = nitro_enclave_machine_initfn,
|
||||||
|
.class_size = sizeof(NitroEnclaveMachineClass),
|
||||||
|
.class_init = nitro_enclave_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nitro_enclave_machine_init(void)
|
||||||
|
{
|
||||||
|
type_register_static(&nitro_enclave_machine_info);
|
||||||
|
}
|
||||||
|
type_init(nitro_enclave_machine_init);
|
@ -6,6 +6,10 @@ config VIRTIO_RNG
|
|||||||
default y
|
default y
|
||||||
depends on VIRTIO
|
depends on VIRTIO
|
||||||
|
|
||||||
|
config VIRTIO_NSM
|
||||||
|
bool
|
||||||
|
depends on LIBCBOR && VIRTIO
|
||||||
|
|
||||||
config VIRTIO_IOMMU
|
config VIRTIO_IOMMU
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
321
hw/virtio/cbor-helpers.c
Normal file
321
hw/virtio/cbor-helpers.c
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* QEMU CBOR helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hw/virtio/cbor-helpers.h"
|
||||||
|
|
||||||
|
bool qemu_cbor_map_add(cbor_item_t *map, cbor_item_t *key, cbor_item_t *value)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
struct cbor_pair pair = (struct cbor_pair) {
|
||||||
|
.key = cbor_move(key),
|
||||||
|
.value = cbor_move(value)
|
||||||
|
};
|
||||||
|
|
||||||
|
success = cbor_map_add(map, pair);
|
||||||
|
if (!success) {
|
||||||
|
cbor_incref(pair.key);
|
||||||
|
cbor_incref(pair.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_array_push(cbor_item_t *array, cbor_item_t *value)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
success = cbor_array_push(array, cbor_move(value));
|
||||||
|
if (!success) {
|
||||||
|
cbor_incref(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_bool_to_map(cbor_item_t *map, const char *key, bool value)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_bool(value);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_uint8(value);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_map_to_map(cbor_item_t *map, const char *key,
|
||||||
|
size_t nested_map_size,
|
||||||
|
cbor_item_t **nested_map)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_new_definite_map(nested_map_size);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
*nested_map = value_cbor;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_bytestring_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t *arr, size_t len)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_bytestring(arr, len);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_null_to_map(cbor_item_t *map, const char *key)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_new_null();
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_string_to_map(cbor_item_t *map, const char *key,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_string(value);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_array_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t *arr, size_t len)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_new_definite_array(len);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
cbor_item_t *tmp = cbor_build_uint8(arr[i]);
|
||||||
|
if (!tmp) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_array_push(value_cbor, tmp)) {
|
||||||
|
cbor_decref(&tmp);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_key_bytestring_to_map(cbor_item_t *map, uint8_t key,
|
||||||
|
uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_uint8(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_bytestring(buf, len);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint64_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
cbor_item_t *key_cbor = NULL;
|
||||||
|
cbor_item_t *value_cbor = NULL;
|
||||||
|
|
||||||
|
key_cbor = cbor_build_string(key);
|
||||||
|
if (!key_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
value_cbor = cbor_build_uint64(value);
|
||||||
|
if (!value_cbor) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (key_cbor) {
|
||||||
|
cbor_decref(&key_cbor);
|
||||||
|
}
|
||||||
|
if (value_cbor) {
|
||||||
|
cbor_decref(&value_cbor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -54,6 +54,7 @@ specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c
|
|||||||
specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c'))
|
specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c'))
|
||||||
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c'))
|
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c'))
|
||||||
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
|
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
|
||||||
|
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm.c', 'cbor-helpers.c'), libcbor])
|
||||||
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
|
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
|
||||||
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c'))
|
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c'))
|
||||||
specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c'))
|
specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c'))
|
||||||
@ -70,6 +71,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pc
|
|||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c'))
|
||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-pci.c'))
|
||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng-pci.c'))
|
||||||
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm-pci.c', 'cbor-helpers.c'), libcbor])
|
||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon-pci.c'))
|
||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-pci.c'))
|
||||||
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio-scsi-pci.c'))
|
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio-scsi-pci.c'))
|
||||||
|
73
hw/virtio/virtio-nsm-pci.c
Normal file
73
hw/virtio/virtio-nsm-pci.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* AWS Nitro Secure Module (NSM) device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "hw/virtio/virtio-pci.h"
|
||||||
|
#include "hw/virtio/virtio-nsm.h"
|
||||||
|
#include "hw/qdev-properties.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/module.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
typedef struct VirtIONsmPCI VirtIONsmPCI;
|
||||||
|
|
||||||
|
#define TYPE_VIRTIO_NSM_PCI "virtio-nsm-pci-base"
|
||||||
|
DECLARE_INSTANCE_CHECKER(VirtIONsmPCI, VIRTIO_NSM_PCI,
|
||||||
|
TYPE_VIRTIO_NSM_PCI)
|
||||||
|
|
||||||
|
struct VirtIONsmPCI {
|
||||||
|
VirtIOPCIProxy parent_obj;
|
||||||
|
VirtIONSM vdev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_nsm_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
|
{
|
||||||
|
VirtIONsmPCI *vnsm = VIRTIO_NSM_PCI(vpci_dev);
|
||||||
|
DeviceState *vdev = DEVICE(&vnsm->vdev);
|
||||||
|
|
||||||
|
virtio_pci_force_virtio_1(vpci_dev);
|
||||||
|
|
||||||
|
if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_nsm_pci_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||||
|
|
||||||
|
k->realize = virtio_nsm_pci_realize;
|
||||||
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_nsm_initfn(Object *obj)
|
||||||
|
{
|
||||||
|
VirtIONsmPCI *dev = VIRTIO_NSM_PCI(obj);
|
||||||
|
|
||||||
|
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||||
|
TYPE_VIRTIO_NSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VirtioPCIDeviceTypeInfo virtio_nsm_pci_info = {
|
||||||
|
.base_name = TYPE_VIRTIO_NSM_PCI,
|
||||||
|
.generic_name = "virtio-nsm-pci",
|
||||||
|
.instance_size = sizeof(VirtIONsmPCI),
|
||||||
|
.instance_init = virtio_nsm_initfn,
|
||||||
|
.class_init = virtio_nsm_pci_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_nsm_pci_register(void)
|
||||||
|
{
|
||||||
|
virtio_pci_types_register(&virtio_nsm_pci_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(virtio_nsm_pci_register)
|
1732
hw/virtio/virtio-nsm.c
Normal file
1732
hw/virtio/virtio-nsm.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -314,6 +314,8 @@ struct MachineClass {
|
|||||||
int64_t (*get_default_cpu_node_id)(const MachineState *ms, int idx);
|
int64_t (*get_default_cpu_node_id)(const MachineState *ms, int idx);
|
||||||
ram_addr_t (*fixup_ram_size)(ram_addr_t size);
|
ram_addr_t (*fixup_ram_size)(ram_addr_t size);
|
||||||
uint64_t smbios_memory_device_size;
|
uint64_t smbios_memory_device_size;
|
||||||
|
bool (*create_default_memdev)(MachineState *ms, const char *path,
|
||||||
|
Error **errp);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +78,8 @@ struct MicrovmMachineClass {
|
|||||||
X86MachineClass parent;
|
X86MachineClass parent;
|
||||||
HotplugHandler *(*orig_hotplug_handler)(MachineState *machine,
|
HotplugHandler *(*orig_hotplug_handler)(MachineState *machine,
|
||||||
DeviceState *dev);
|
DeviceState *dev);
|
||||||
|
void (*x86_load_linux)(X86MachineState *x86ms, FWCfgState *fw_cfg,
|
||||||
|
int acpi_data_size, bool pvh_enabled);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MicrovmMachineState {
|
struct MicrovmMachineState {
|
||||||
|
62
include/hw/i386/nitro_enclave.h
Normal file
62
include/hw/i386/nitro_enclave.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* AWS nitro-enclave machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_I386_NITRO_ENCLAVE_H
|
||||||
|
#define HW_I386_NITRO_ENCLAVE_H
|
||||||
|
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "hw/i386/microvm.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
#include "hw/virtio/virtio-nsm.h"
|
||||||
|
|
||||||
|
/* Machine type options */
|
||||||
|
#define NITRO_ENCLAVE_VSOCK_CHARDEV_ID "vsock"
|
||||||
|
#define NITRO_ENCLAVE_ID "id"
|
||||||
|
#define NITRO_ENCLAVE_PARENT_ROLE "parent-role"
|
||||||
|
#define NITRO_ENCLAVE_PARENT_ID "parent-id"
|
||||||
|
|
||||||
|
struct NitroEnclaveMachineClass {
|
||||||
|
MicrovmMachineClass parent;
|
||||||
|
|
||||||
|
void (*parent_init)(MachineState *state);
|
||||||
|
void (*parent_reset)(MachineState *machine, ResetType type);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NitroEnclaveMachineState {
|
||||||
|
MicrovmMachineState parent;
|
||||||
|
|
||||||
|
/* Machine type options */
|
||||||
|
char *vsock;
|
||||||
|
/* Enclave identifier */
|
||||||
|
char *id;
|
||||||
|
/* Parent instance IAM role ARN */
|
||||||
|
char *parent_role;
|
||||||
|
/* Parent instance identifier */
|
||||||
|
char *parent_id;
|
||||||
|
|
||||||
|
/* Machine state */
|
||||||
|
VirtIONSM *vnsm;
|
||||||
|
|
||||||
|
/* kernel + ramdisks + cmdline sha384 hash */
|
||||||
|
uint8_t image_sha384[QCRYPTO_HASH_DIGEST_LEN_SHA384];
|
||||||
|
/* kernel + boot ramdisk + cmdline sha384 hash */
|
||||||
|
uint8_t bootstrap_sha384[QCRYPTO_HASH_DIGEST_LEN_SHA384];
|
||||||
|
/* application ramdisk(s) hash */
|
||||||
|
uint8_t app_sha384[QCRYPTO_HASH_DIGEST_LEN_SHA384];
|
||||||
|
/* certificate fingerprint hash */
|
||||||
|
uint8_t fingerprint_sha384[QCRYPTO_HASH_DIGEST_LEN_SHA384];
|
||||||
|
bool signature_found;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TYPE_NITRO_ENCLAVE_MACHINE MACHINE_TYPE_NAME("nitro-enclave")
|
||||||
|
OBJECT_DECLARE_TYPE(NitroEnclaveMachineState, NitroEnclaveMachineClass,
|
||||||
|
NITRO_ENCLAVE_MACHINE)
|
||||||
|
|
||||||
|
#endif
|
45
include/hw/virtio/cbor-helpers.h
Normal file
45
include/hw/virtio/cbor-helpers.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* QEMU CBOR helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QEMU_VIRTIO_CBOR_HELPERS_H
|
||||||
|
#define QEMU_VIRTIO_CBOR_HELPERS_H
|
||||||
|
|
||||||
|
#include <cbor.h>
|
||||||
|
|
||||||
|
bool qemu_cbor_map_add(cbor_item_t *map, cbor_item_t *key, cbor_item_t *value);
|
||||||
|
|
||||||
|
bool qemu_cbor_array_push(cbor_item_t *array, cbor_item_t *value);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_bool_to_map(cbor_item_t *map, const char *key, bool value);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t value);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_map_to_map(cbor_item_t *map, const char *key,
|
||||||
|
size_t nested_map_size,
|
||||||
|
cbor_item_t **nested_map);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_bytestring_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t *arr, size_t len);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_null_to_map(cbor_item_t *map, const char *key);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_string_to_map(cbor_item_t *map, const char *key,
|
||||||
|
const char *value);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_array_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint8_t *arr, size_t len);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint8_key_bytestring_to_map(cbor_item_t *map, uint8_t key,
|
||||||
|
uint8_t *buf, size_t len);
|
||||||
|
|
||||||
|
bool qemu_cbor_add_uint64_to_map(cbor_item_t *map, const char *key,
|
||||||
|
uint64_t value);
|
||||||
|
#endif
|
49
include/hw/virtio/virtio-nsm.h
Normal file
49
include/hw/virtio/virtio-nsm.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* AWS Nitro Secure Module (NSM) device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
* (at your option) any later version. See the COPYING file in the
|
||||||
|
* top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QEMU_VIRTIO_NSM_H
|
||||||
|
#define QEMU_VIRTIO_NSM_H
|
||||||
|
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "hw/virtio/virtio.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
#define NSM_MAX_PCRS 32
|
||||||
|
|
||||||
|
#define TYPE_VIRTIO_NSM "virtio-nsm-device"
|
||||||
|
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONSM, VIRTIO_NSM)
|
||||||
|
#define VIRTIO_NSM_GET_PARENT_CLASS(obj) \
|
||||||
|
OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_NSM)
|
||||||
|
|
||||||
|
struct PCRInfo {
|
||||||
|
bool locked;
|
||||||
|
uint8_t data[QCRYPTO_HASH_DIGEST_LEN_SHA384];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VirtIONSM {
|
||||||
|
VirtIODevice parent_obj;
|
||||||
|
|
||||||
|
/* Only one vq - guest puts request and response buffers on it */
|
||||||
|
VirtQueue *vq;
|
||||||
|
|
||||||
|
/* NSM State */
|
||||||
|
uint16_t max_pcrs;
|
||||||
|
struct PCRInfo pcrs[NSM_MAX_PCRS];
|
||||||
|
char *digest;
|
||||||
|
char *module_id;
|
||||||
|
uint8_t version_major;
|
||||||
|
uint8_t version_minor;
|
||||||
|
uint8_t version_patch;
|
||||||
|
|
||||||
|
bool (*extend_pcr)(VirtIONSM *vnsm, int ind, uint8_t *data, uint16_t len);
|
||||||
|
void (*lock_pcr)(VirtIONSM *vnsm, int ind);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -313,6 +313,15 @@ static inline int ctpop8(uint8_t val)
|
|||||||
return __builtin_popcount(val);
|
return __builtin_popcount(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parity8 - return the parity (1 = odd) of an 8-bit value.
|
||||||
|
* @val: The value to search
|
||||||
|
*/
|
||||||
|
static inline int parity8(uint8_t val)
|
||||||
|
{
|
||||||
|
return __builtin_parity(val);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ctpop16 - count the population of one bits in a 16-bit value.
|
* ctpop16 - count the population of one bits in a 16-bit value.
|
||||||
* @val: The value to search
|
* @val: The value to search
|
||||||
|
@ -2032,14 +2032,6 @@ int object_child_foreach_recursive(Object *obj,
|
|||||||
*/
|
*/
|
||||||
Object *container_get(Object *root, const char *path);
|
Object *container_get(Object *root, const char *path);
|
||||||
|
|
||||||
/**
|
|
||||||
* object_type_get_instance_size:
|
|
||||||
* @typename: Name of the Type whose instance_size is required
|
|
||||||
*
|
|
||||||
* Returns the instance_size of the given @typename.
|
|
||||||
*/
|
|
||||||
size_t object_type_get_instance_size(const char *typename);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* object_property_help:
|
* object_property_help:
|
||||||
* @name: the name of the property
|
* @name: the name of the property
|
||||||
|
@ -39,6 +39,8 @@ OBJECT_DECLARE_TYPE(HostMemoryBackend, HostMemoryBackendClass,
|
|||||||
*/
|
*/
|
||||||
#define TYPE_MEMORY_BACKEND_FILE "memory-backend-file"
|
#define TYPE_MEMORY_BACKEND_FILE "memory-backend-file"
|
||||||
|
|
||||||
|
#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HostMemoryBackendClass:
|
* HostMemoryBackendClass:
|
||||||
|
17
meson.build
17
meson.build
@ -1716,6 +1716,12 @@ if (have_system or have_tools) and (virgl.found() or opengl.found())
|
|||||||
endif
|
endif
|
||||||
have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found()
|
have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found()
|
||||||
|
|
||||||
|
libcbor = not_found
|
||||||
|
if not get_option('libcbor').auto() or have_system
|
||||||
|
libcbor = dependency('libcbor', version: '>=0.7.0',
|
||||||
|
required: get_option('libcbor'))
|
||||||
|
endif
|
||||||
|
|
||||||
gnutls = not_found
|
gnutls = not_found
|
||||||
gnutls_crypto = not_found
|
gnutls_crypto = not_found
|
||||||
if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
|
if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
|
||||||
@ -3127,6 +3133,8 @@ host_kconfig = \
|
|||||||
(spice.found() ? ['CONFIG_SPICE=y'] : []) + \
|
(spice.found() ? ['CONFIG_SPICE=y'] : []) + \
|
||||||
(have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
|
(have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
|
||||||
(opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \
|
(opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \
|
||||||
|
(libcbor.found() ? ['CONFIG_LIBCBOR=y'] : []) + \
|
||||||
|
(gnutls.found() ? ['CONFIG_GNUTLS=y'] : []) + \
|
||||||
(x11.found() ? ['CONFIG_X11=y'] : []) + \
|
(x11.found() ? ['CONFIG_X11=y'] : []) + \
|
||||||
(fdt.found() ? ['CONFIG_FDT=y'] : []) + \
|
(fdt.found() ? ['CONFIG_FDT=y'] : []) + \
|
||||||
(have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \
|
(have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \
|
||||||
@ -4694,6 +4702,7 @@ summary_info += {'NUMA host support': numa}
|
|||||||
summary_info += {'capstone': capstone}
|
summary_info += {'capstone': capstone}
|
||||||
summary_info += {'libpmem support': libpmem}
|
summary_info += {'libpmem support': libpmem}
|
||||||
summary_info += {'libdaxctl support': libdaxctl}
|
summary_info += {'libdaxctl support': libdaxctl}
|
||||||
|
summary_info += {'libcbor support': libcbor}
|
||||||
summary_info += {'libudev': libudev}
|
summary_info += {'libudev': libudev}
|
||||||
# Dummy dependency, keep .found()
|
# Dummy dependency, keep .found()
|
||||||
summary_info += {'FUSE lseek': fuse_lseek.found()}
|
summary_info += {'FUSE lseek': fuse_lseek.found()}
|
||||||
@ -4718,6 +4727,14 @@ if host_arch == 'unknown'
|
|||||||
message('configure has succeeded and you can continue to build, but')
|
message('configure has succeeded and you can continue to build, but')
|
||||||
message('QEMU will use a slow interpreter to emulate the target CPU.')
|
message('QEMU will use a slow interpreter to emulate the target CPU.')
|
||||||
endif
|
endif
|
||||||
|
elif host_arch == 'mips'
|
||||||
|
message()
|
||||||
|
warning('DEPRECATED HOST CPU')
|
||||||
|
message()
|
||||||
|
message('Support for CPU host architecture ' + cpu + ' is going to be')
|
||||||
|
message('dropped as soon as the QEMU project stops supporting Debian 12')
|
||||||
|
message('("Bookworm"). Going forward, the QEMU project will not guarantee')
|
||||||
|
message('that QEMU will compile or work on this host CPU.')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if not supported_oses.contains(host_os)
|
if not supported_oses.contains(host_os)
|
||||||
|
@ -168,6 +168,8 @@ option('iconv', type : 'feature', value : 'auto',
|
|||||||
description: 'Font glyph conversion support')
|
description: 'Font glyph conversion support')
|
||||||
option('curses', type : 'feature', value : 'auto',
|
option('curses', type : 'feature', value : 'auto',
|
||||||
description: 'curses UI')
|
description: 'curses UI')
|
||||||
|
option('libcbor', type : 'feature', value : 'auto',
|
||||||
|
description: 'libcbor support')
|
||||||
option('gnutls', type : 'feature', value : 'auto',
|
option('gnutls', type : 'feature', value : 'auto',
|
||||||
description: 'GNUTLS cryptography support')
|
description: 'GNUTLS cryptography support')
|
||||||
option('nettle', type : 'feature', value : 'auto',
|
option('nettle', type : 'feature', value : 'auto',
|
||||||
|
80
qom/object.c
80
qom/object.c
@ -195,7 +195,7 @@ void type_register_static_array(const TypeInfo *infos, int nr_infos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeImpl *type_get_by_name(const char *name)
|
static TypeImpl *type_get_by_name_noload(const char *name)
|
||||||
{
|
{
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -204,10 +204,32 @@ static TypeImpl *type_get_by_name(const char *name)
|
|||||||
return type_table_lookup(name);
|
return type_table_lookup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TypeImpl *type_get_or_load_by_name(const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
TypeImpl *type = type_get_by_name_noload(name);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MODULES
|
||||||
|
if (!type) {
|
||||||
|
int rv = module_load_qom(name, errp);
|
||||||
|
if (rv > 0) {
|
||||||
|
type = type_get_by_name_noload(name);
|
||||||
|
} else {
|
||||||
|
error_prepend(errp, "could not load a module for type '%s'", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!type) {
|
||||||
|
error_setg(errp, "unknown type '%s'", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
static TypeImpl *type_get_parent(TypeImpl *type)
|
static TypeImpl *type_get_parent(TypeImpl *type)
|
||||||
{
|
{
|
||||||
if (!type->parent_type && type->parent) {
|
if (!type->parent_type && type->parent) {
|
||||||
type->parent_type = type_get_by_name(type->parent);
|
type->parent_type = type_get_by_name_noload(type->parent);
|
||||||
if (!type->parent_type) {
|
if (!type->parent_type) {
|
||||||
fprintf(stderr, "Type '%s' is missing its parent '%s'\n",
|
fprintf(stderr, "Type '%s' is missing its parent '%s'\n",
|
||||||
type->name, type->parent);
|
type->name, type->parent);
|
||||||
@ -262,14 +284,6 @@ static size_t type_object_get_align(TypeImpl *ti)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t object_type_get_instance_size(const char *typename)
|
|
||||||
{
|
|
||||||
TypeImpl *type = type_get_by_name(typename);
|
|
||||||
|
|
||||||
g_assert(type != NULL);
|
|
||||||
return type_object_get_size(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
|
static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
|
||||||
{
|
{
|
||||||
assert(target_type);
|
assert(target_type);
|
||||||
@ -371,7 +385,7 @@ static void type_initialize(TypeImpl *ti)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ti->num_interfaces; i++) {
|
for (i = 0; i < ti->num_interfaces; i++) {
|
||||||
TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
|
TypeImpl *t = type_get_by_name_noload(ti->interfaces[i].typename);
|
||||||
if (!t) {
|
if (!t) {
|
||||||
error_report("missing interface '%s' for object '%s'",
|
error_report("missing interface '%s' for object '%s'",
|
||||||
ti->interfaces[i].typename, parent->name);
|
ti->interfaces[i].typename, parent->name);
|
||||||
@ -565,23 +579,7 @@ static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type
|
|||||||
|
|
||||||
void object_initialize(void *data, size_t size, const char *typename)
|
void object_initialize(void *data, size_t size, const char *typename)
|
||||||
{
|
{
|
||||||
TypeImpl *type = type_get_by_name(typename);
|
TypeImpl *type = type_get_or_load_by_name(typename, &error_fatal);
|
||||||
|
|
||||||
#ifdef CONFIG_MODULES
|
|
||||||
if (!type) {
|
|
||||||
int rv = module_load_qom(typename, &error_fatal);
|
|
||||||
if (rv > 0) {
|
|
||||||
type = type_get_by_name(typename);
|
|
||||||
} else {
|
|
||||||
error_report("missing object type '%s'", typename);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!type) {
|
|
||||||
error_report("missing object type '%s'", typename);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
object_initialize_with_type(data, size, type);
|
object_initialize_with_type(data, size, type);
|
||||||
}
|
}
|
||||||
@ -792,7 +790,7 @@ Object *object_new_with_class(ObjectClass *klass)
|
|||||||
|
|
||||||
Object *object_new(const char *typename)
|
Object *object_new(const char *typename)
|
||||||
{
|
{
|
||||||
TypeImpl *ti = type_get_by_name(typename);
|
TypeImpl *ti = type_get_or_load_by_name(typename, &error_fatal);
|
||||||
|
|
||||||
return object_new_with_type(ti);
|
return object_new_with_type(ti);
|
||||||
}
|
}
|
||||||
@ -965,7 +963,7 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
|
|||||||
return class;
|
return class;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_type = type_get_by_name(typename);
|
target_type = type_get_by_name_noload(typename);
|
||||||
if (!target_type) {
|
if (!target_type) {
|
||||||
/* target class type unknown, so fail the cast */
|
/* target class type unknown, so fail the cast */
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1063,7 +1061,7 @@ const char *object_class_get_name(ObjectClass *klass)
|
|||||||
|
|
||||||
ObjectClass *object_class_by_name(const char *typename)
|
ObjectClass *object_class_by_name(const char *typename)
|
||||||
{
|
{
|
||||||
TypeImpl *type = type_get_by_name(typename);
|
TypeImpl *type = type_get_by_name_noload(typename);
|
||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1076,21 +1074,15 @@ ObjectClass *object_class_by_name(const char *typename)
|
|||||||
|
|
||||||
ObjectClass *module_object_class_by_name(const char *typename)
|
ObjectClass *module_object_class_by_name(const char *typename)
|
||||||
{
|
{
|
||||||
ObjectClass *oc;
|
TypeImpl *type = type_get_or_load_by_name(typename, NULL);
|
||||||
|
|
||||||
oc = object_class_by_name(typename);
|
if (!type) {
|
||||||
#ifdef CONFIG_MODULES
|
return NULL;
|
||||||
if (!oc) {
|
|
||||||
Error *local_err = NULL;
|
|
||||||
int rv = module_load_qom(typename, &local_err);
|
|
||||||
if (rv > 0) {
|
|
||||||
oc = object_class_by_name(typename);
|
|
||||||
} else if (rv < 0) {
|
|
||||||
error_report_err(local_err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return oc;
|
type_initialize(type);
|
||||||
|
|
||||||
|
return type->class;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectClass *object_class_get_parent(ObjectClass *class)
|
ObjectClass *object_class_get_parent(ObjectClass *class)
|
||||||
|
@ -90,7 +90,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
klass = object_class_by_name(type);
|
klass = module_object_class_by_name(type);
|
||||||
if (!klass) {
|
if (!klass) {
|
||||||
error_setg(errp, "invalid object type: %s", type);
|
error_setg(errp, "invalid object type: %s", type);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -108,7 +108,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(qdict);
|
assert(qdict);
|
||||||
obj = object_new(type);
|
obj = object_new_with_class(klass);
|
||||||
object_set_properties_from_qdict(obj, qdict, v, &local_err);
|
object_set_properties_from_qdict(obj, qdict, v, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -141,7 +141,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = object_new(typename);
|
obj = object_new_with_class(klass);
|
||||||
|
|
||||||
object_property_iter_init(&iter, obj);
|
object_property_iter_init(&iter, obj);
|
||||||
while ((prop = object_property_iter_next(&iter))) {
|
while ((prop = object_property_iter_next(&iter))) {
|
||||||
@ -186,7 +186,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
|
|||||||
ObjectPropertyIterator iter;
|
ObjectPropertyIterator iter;
|
||||||
ObjectPropertyInfoList *prop_list = NULL;
|
ObjectPropertyInfoList *prop_list = NULL;
|
||||||
|
|
||||||
klass = object_class_by_name(typename);
|
klass = module_object_class_by_name(typename);
|
||||||
if (klass == NULL) {
|
if (klass == NULL) {
|
||||||
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
||||||
"Class '%s' not found", typename);
|
"Class '%s' not found", typename);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
packages:
|
packages:
|
||||||
- bash
|
- bash
|
||||||
- bc
|
- bc
|
||||||
|
- bindgen
|
||||||
- bison
|
- bison
|
||||||
- bsdextrautils
|
- bsdextrautils
|
||||||
- bzip2
|
- bzip2
|
||||||
@ -35,6 +36,7 @@ packages:
|
|||||||
- libcacard-dev
|
- libcacard-dev
|
||||||
- libcap-ng-dev
|
- libcap-ng-dev
|
||||||
- libcapstone-dev
|
- libcapstone-dev
|
||||||
|
- libcbor-dev
|
||||||
- libcmocka-dev
|
- libcmocka-dev
|
||||||
- libcurl4-gnutls-dev
|
- libcurl4-gnutls-dev
|
||||||
- libdaxctl-dev
|
- libdaxctl-dev
|
||||||
@ -113,6 +115,7 @@ packages:
|
|||||||
- python3-venv
|
- python3-venv
|
||||||
- python3-yaml
|
- python3-yaml
|
||||||
- rpm2cpio
|
- rpm2cpio
|
||||||
|
- rustc
|
||||||
- sed
|
- sed
|
||||||
- socat
|
- socat
|
||||||
- sparse
|
- sparse
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
packages:
|
packages:
|
||||||
- bash
|
- bash
|
||||||
- bc
|
- bc
|
||||||
|
- bindgen
|
||||||
- bison
|
- bison
|
||||||
- bsdextrautils
|
- bsdextrautils
|
||||||
- bzip2
|
- bzip2
|
||||||
@ -35,6 +36,7 @@ packages:
|
|||||||
- libcacard-dev
|
- libcacard-dev
|
||||||
- libcap-ng-dev
|
- libcap-ng-dev
|
||||||
- libcapstone-dev
|
- libcapstone-dev
|
||||||
|
- libcbor-dev
|
||||||
- libcmocka-dev
|
- libcmocka-dev
|
||||||
- libcurl4-gnutls-dev
|
- libcurl4-gnutls-dev
|
||||||
- libdaxctl-dev
|
- libdaxctl-dev
|
||||||
@ -111,6 +113,7 @@ packages:
|
|||||||
- python3-venv
|
- python3-venv
|
||||||
- python3-yaml
|
- python3-yaml
|
||||||
- rpm2cpio
|
- rpm2cpio
|
||||||
|
- rustc
|
||||||
- sed
|
- sed
|
||||||
- socat
|
- socat
|
||||||
- sparse
|
- sparse
|
||||||
|
@ -133,6 +133,7 @@ meson_options_help() {
|
|||||||
printf "%s\n" ' keyring Linux keyring support'
|
printf "%s\n" ' keyring Linux keyring support'
|
||||||
printf "%s\n" ' kvm KVM acceleration support'
|
printf "%s\n" ' kvm KVM acceleration support'
|
||||||
printf "%s\n" ' l2tpv3 l2tpv3 network backend support'
|
printf "%s\n" ' l2tpv3 l2tpv3 network backend support'
|
||||||
|
printf "%s\n" ' libcbor libcbor support'
|
||||||
printf "%s\n" ' libdaxctl libdaxctl support'
|
printf "%s\n" ' libdaxctl libdaxctl support'
|
||||||
printf "%s\n" ' libdw debuginfo support'
|
printf "%s\n" ' libdw debuginfo support'
|
||||||
printf "%s\n" ' libiscsi libiscsi userspace initiator'
|
printf "%s\n" ' libiscsi libiscsi userspace initiator'
|
||||||
@ -358,6 +359,8 @@ _meson_option_parse() {
|
|||||||
--disable-kvm) printf "%s" -Dkvm=disabled ;;
|
--disable-kvm) printf "%s" -Dkvm=disabled ;;
|
||||||
--enable-l2tpv3) printf "%s" -Dl2tpv3=enabled ;;
|
--enable-l2tpv3) printf "%s" -Dl2tpv3=enabled ;;
|
||||||
--disable-l2tpv3) printf "%s" -Dl2tpv3=disabled ;;
|
--disable-l2tpv3) printf "%s" -Dl2tpv3=disabled ;;
|
||||||
|
--enable-libcbor) printf "%s" -Dlibcbor=enabled ;;
|
||||||
|
--disable-libcbor) printf "%s" -Dlibcbor=disabled ;;
|
||||||
--enable-libdaxctl) printf "%s" -Dlibdaxctl=enabled ;;
|
--enable-libdaxctl) printf "%s" -Dlibdaxctl=enabled ;;
|
||||||
--disable-libdaxctl) printf "%s" -Dlibdaxctl=disabled ;;
|
--disable-libdaxctl) printf "%s" -Dlibdaxctl=disabled ;;
|
||||||
--libdir=*) quote_sh "-Dlibdir=$2" ;;
|
--libdir=*) quote_sh "-Dlibdir=$2" ;;
|
||||||
|
@ -55,7 +55,12 @@ endif
|
|||||||
if have_user
|
if have_user
|
||||||
# Symbols that are used by hw/core.
|
# Symbols that are used by hw/core.
|
||||||
stub_ss.add(files('cpu-synchronize-state.c'))
|
stub_ss.add(files('cpu-synchronize-state.c'))
|
||||||
stub_ss.add(files('qdev.c'))
|
|
||||||
|
# Stubs for QAPI events. Those can always be included in the build, but
|
||||||
|
# they are not built at all for --disable-system --disable-tools builds.
|
||||||
|
if not (have_system or have_tools)
|
||||||
|
stub_ss.add(files('qdev.c'))
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if have_system
|
if have_system
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* x86 debug */
|
/* x86 debug */
|
||||||
|
|
||||||
static const char *cc_op_str[CC_OP_NB] = {
|
static const char * const cc_op_str[] = {
|
||||||
[CC_OP_DYNAMIC] = "DYNAMIC",
|
[CC_OP_DYNAMIC] = "DYNAMIC",
|
||||||
|
|
||||||
[CC_OP_EFLAGS] = "EFLAGS",
|
[CC_OP_EFLAGS] = "EFLAGS",
|
||||||
@ -91,7 +91,6 @@ static const char *cc_op_str[CC_OP_NB] = {
|
|||||||
[CC_OP_BMILGQ] = "BMILGQ",
|
[CC_OP_BMILGQ] = "BMILGQ",
|
||||||
|
|
||||||
[CC_OP_POPCNT] = "POPCNT",
|
[CC_OP_POPCNT] = "POPCNT",
|
||||||
[CC_OP_CLR] = "CLR",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -347,7 +346,6 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|||||||
X86CPU *cpu = X86_CPU(cs);
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
int eflags, i, nb;
|
int eflags, i, nb;
|
||||||
char cc_op_name[32];
|
|
||||||
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
|
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
|
||||||
|
|
||||||
eflags = cpu_compute_eflags(env);
|
eflags = cpu_compute_eflags(env);
|
||||||
@ -456,10 +454,16 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|||||||
env->dr[6], env->dr[7]);
|
env->dr[6], env->dr[7]);
|
||||||
}
|
}
|
||||||
if (flags & CPU_DUMP_CCOP) {
|
if (flags & CPU_DUMP_CCOP) {
|
||||||
if ((unsigned)env->cc_op < CC_OP_NB)
|
const char *cc_op_name = NULL;
|
||||||
snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
|
char cc_op_buf[32];
|
||||||
else
|
|
||||||
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
|
if ((unsigned)env->cc_op < ARRAY_SIZE(cc_op_str)) {
|
||||||
|
cc_op_name = cc_op_str[env->cc_op];
|
||||||
|
}
|
||||||
|
if (cc_op_name == NULL) {
|
||||||
|
snprintf(cc_op_buf, sizeof(cc_op_buf), "[%d]", env->cc_op);
|
||||||
|
cc_op_name = cc_op_buf;
|
||||||
|
}
|
||||||
#ifdef TARGET_X86_64
|
#ifdef TARGET_X86_64
|
||||||
if (env->hflags & HF_CS64_MASK) {
|
if (env->hflags & HF_CS64_MASK) {
|
||||||
qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
|
qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
|
||||||
|
@ -46,6 +46,9 @@
|
|||||||
#include "cpu-internal.h"
|
#include "cpu-internal.h"
|
||||||
|
|
||||||
static void x86_cpu_realizefn(DeviceState *dev, Error **errp);
|
static void x86_cpu_realizefn(DeviceState *dev, Error **errp);
|
||||||
|
static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index,
|
||||||
|
uint32_t *eax, uint32_t *ebx,
|
||||||
|
uint32_t *ecx, uint32_t *edx);
|
||||||
|
|
||||||
/* Helpers for building CPUID[2] descriptors: */
|
/* Helpers for building CPUID[2] descriptors: */
|
||||||
|
|
||||||
@ -898,6 +901,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
|||||||
#define TCG_SGX_12_0_EAX_FEATURES 0
|
#define TCG_SGX_12_0_EAX_FEATURES 0
|
||||||
#define TCG_SGX_12_0_EBX_FEATURES 0
|
#define TCG_SGX_12_0_EBX_FEATURES 0
|
||||||
#define TCG_SGX_12_1_EAX_FEATURES 0
|
#define TCG_SGX_12_1_EAX_FEATURES 0
|
||||||
|
#define TCG_24_0_EBX_FEATURES 0
|
||||||
|
|
||||||
#if defined CONFIG_USER_ONLY
|
#if defined CONFIG_USER_ONLY
|
||||||
#define CPUID_8000_0008_EBX_KERNEL_FEATURES (CPUID_8000_0008_EBX_IBPB | \
|
#define CPUID_8000_0008_EBX_KERNEL_FEATURES (CPUID_8000_0008_EBX_IBPB | \
|
||||||
@ -1132,7 +1136,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
"avx-vnni-int8", "avx-ne-convert", NULL, NULL,
|
"avx-vnni-int8", "avx-ne-convert", NULL, NULL,
|
||||||
"amx-complex", NULL, "avx-vnni-int16", NULL,
|
"amx-complex", NULL, "avx-vnni-int16", NULL,
|
||||||
NULL, NULL, "prefetchiti", NULL,
|
NULL, NULL, "prefetchiti", NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, "avx10",
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
@ -1163,6 +1167,20 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
},
|
},
|
||||||
.tcg_features = TCG_7_2_EDX_FEATURES,
|
.tcg_features = TCG_7_2_EDX_FEATURES,
|
||||||
},
|
},
|
||||||
|
[FEAT_24_0_EBX] = {
|
||||||
|
.type = CPUID_FEATURE_WORD,
|
||||||
|
.feat_names = {
|
||||||
|
[16] = "avx10-128",
|
||||||
|
[17] = "avx10-256",
|
||||||
|
[18] = "avx10-512",
|
||||||
|
},
|
||||||
|
.cpuid = {
|
||||||
|
.eax = 0x24,
|
||||||
|
.needs_ecx = true, .ecx = 0,
|
||||||
|
.reg = R_EBX,
|
||||||
|
},
|
||||||
|
.tcg_features = TCG_24_0_EBX_FEATURES,
|
||||||
|
},
|
||||||
[FEAT_8000_0007_EDX] = {
|
[FEAT_8000_0007_EDX] = {
|
||||||
.type = CPUID_FEATURE_WORD,
|
.type = CPUID_FEATURE_WORD,
|
||||||
.feat_names = {
|
.feat_names = {
|
||||||
@ -1220,13 +1238,35 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, "sbpb",
|
"eraps", NULL, NULL, "sbpb",
|
||||||
"ibpb-brtype", NULL, NULL, NULL,
|
"ibpb-brtype", "srso-no", "srso-user-kernel-no", NULL,
|
||||||
},
|
},
|
||||||
.cpuid = { .eax = 0x80000021, .reg = R_EAX, },
|
.cpuid = { .eax = 0x80000021, .reg = R_EAX, },
|
||||||
.tcg_features = 0,
|
.tcg_features = 0,
|
||||||
.unmigratable_flags = 0,
|
.unmigratable_flags = 0,
|
||||||
},
|
},
|
||||||
|
[FEAT_8000_0021_EBX] = {
|
||||||
|
.type = CPUID_FEATURE_WORD,
|
||||||
|
.cpuid = { .eax = 0x80000021, .reg = R_EBX, },
|
||||||
|
.tcg_features = 0,
|
||||||
|
.unmigratable_flags = 0,
|
||||||
|
},
|
||||||
|
[FEAT_8000_0022_EAX] = {
|
||||||
|
.type = CPUID_FEATURE_WORD,
|
||||||
|
.feat_names = {
|
||||||
|
"perfmon-v2", NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
},
|
||||||
|
.cpuid = { .eax = 0x80000022, .reg = R_EAX, },
|
||||||
|
.tcg_features = 0,
|
||||||
|
.unmigratable_flags = 0,
|
||||||
|
},
|
||||||
[FEAT_XSAVE] = {
|
[FEAT_XSAVE] = {
|
||||||
.type = CPUID_FEATURE_WORD,
|
.type = CPUID_FEATURE_WORD,
|
||||||
.feat_names = {
|
.feat_names = {
|
||||||
@ -1296,7 +1336,9 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
.needs_ecx = true, .ecx = 0,
|
.needs_ecx = true, .ecx = 0,
|
||||||
.reg = R_EAX,
|
.reg = R_EAX,
|
||||||
},
|
},
|
||||||
.tcg_features = ~0U,
|
.tcg_features = XSTATE_FP_MASK | XSTATE_SSE_MASK |
|
||||||
|
XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
|
||||||
|
XSTATE_PKRU_MASK,
|
||||||
.migratable_flags = XSTATE_FP_MASK | XSTATE_SSE_MASK |
|
.migratable_flags = XSTATE_FP_MASK | XSTATE_SSE_MASK |
|
||||||
XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
|
XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
|
||||||
XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK |
|
XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK |
|
||||||
@ -1309,7 +1351,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||||||
.needs_ecx = true, .ecx = 0,
|
.needs_ecx = true, .ecx = 0,
|
||||||
.reg = R_EDX,
|
.reg = R_EDX,
|
||||||
},
|
},
|
||||||
.tcg_features = ~0U,
|
.tcg_features = 0U,
|
||||||
},
|
},
|
||||||
/*Below are MSR exposed features*/
|
/*Below are MSR exposed features*/
|
||||||
[FEAT_ARCH_CAPABILITIES] = {
|
[FEAT_ARCH_CAPABILITIES] = {
|
||||||
@ -1745,6 +1787,22 @@ static FeatureDep feature_dependencies[] = {
|
|||||||
.from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
|
.from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
|
||||||
.to = { FEAT_SGX_12_1_EAX, ~0ull },
|
.to = { FEAT_SGX_12_1_EAX, ~0ull },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_128 },
|
||||||
|
.to = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_256 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_256 },
|
||||||
|
.to = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_512 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_VL_MASK },
|
||||||
|
.to = { FEAT_7_1_EDX, CPUID_7_1_EDX_AVX10 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.from = { FEAT_7_1_EDX, CPUID_7_1_EDX_AVX10 },
|
||||||
|
.to = { FEAT_24_0_EBX, ~0ull },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct X86RegisterInfo32 {
|
typedef struct X86RegisterInfo32 {
|
||||||
@ -1965,6 +2023,7 @@ typedef struct X86CPUDefinition {
|
|||||||
int family;
|
int family;
|
||||||
int model;
|
int model;
|
||||||
int stepping;
|
int stepping;
|
||||||
|
uint8_t avx10_version;
|
||||||
FeatureWordArray features;
|
FeatureWordArray features;
|
||||||
const char *model_id;
|
const char *model_id;
|
||||||
const CPUCaches *const cache_info;
|
const CPUCaches *const cache_info;
|
||||||
@ -4344,6 +4403,23 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||||||
.model_id = "Intel Xeon Processor (GraniteRapids)",
|
.model_id = "Intel Xeon Processor (GraniteRapids)",
|
||||||
.versions = (X86CPUVersionDefinition[]) {
|
.versions = (X86CPUVersionDefinition[]) {
|
||||||
{ .version = 1 },
|
{ .version = 1 },
|
||||||
|
{
|
||||||
|
.version = 2,
|
||||||
|
.props = (PropValue[]) {
|
||||||
|
{ "ss", "on" },
|
||||||
|
{ "tsc-adjust", "on" },
|
||||||
|
{ "cldemote", "on" },
|
||||||
|
{ "movdiri", "on" },
|
||||||
|
{ "movdir64b", "on" },
|
||||||
|
{ "avx10", "on" },
|
||||||
|
{ "avx10-128", "on" },
|
||||||
|
{ "avx10-256", "on" },
|
||||||
|
{ "avx10-512", "on" },
|
||||||
|
{ "avx10-version", "1" },
|
||||||
|
{ "stepping", "1" },
|
||||||
|
{ /* end of list */ }
|
||||||
|
}
|
||||||
|
},
|
||||||
{ /* end of list */ },
|
{ /* end of list */ },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -5226,7 +5302,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
|||||||
CPUID_8000_0008_EBX_STIBP_ALWAYS_ON |
|
CPUID_8000_0008_EBX_STIBP_ALWAYS_ON |
|
||||||
CPUID_8000_0008_EBX_AMD_SSBD | CPUID_8000_0008_EBX_AMD_PSFD,
|
CPUID_8000_0008_EBX_AMD_SSBD | CPUID_8000_0008_EBX_AMD_PSFD,
|
||||||
.features[FEAT_8000_0021_EAX] =
|
.features[FEAT_8000_0021_EAX] =
|
||||||
CPUID_8000_0021_EAX_No_NESTED_DATA_BP |
|
CPUID_8000_0021_EAX_NO_NESTED_DATA_BP |
|
||||||
CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING |
|
CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING |
|
||||||
CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE |
|
CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE |
|
||||||
CPUID_8000_0021_EAX_AUTO_IBRS,
|
CPUID_8000_0021_EAX_AUTO_IBRS,
|
||||||
@ -5816,7 +5892,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x86_cpu_filter_features(X86CPU *cpu, bool verbose);
|
static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose);
|
||||||
|
|
||||||
/* Build a list with the name of all features on a feature word array */
|
/* Build a list with the name of all features on a feature word array */
|
||||||
static void x86_cpu_list_feature_names(FeatureWordArray features,
|
static void x86_cpu_list_feature_names(FeatureWordArray features,
|
||||||
@ -6307,6 +6383,9 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
|
|||||||
*/
|
*/
|
||||||
object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort);
|
object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort);
|
||||||
|
|
||||||
|
object_property_set_uint(OBJECT(cpu), "avx10-version", def->avx10_version,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
x86_cpu_apply_version_props(cpu, model);
|
x86_cpu_apply_version_props(cpu, model);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -6835,6 +6914,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 0x24: {
|
||||||
|
*eax = 0;
|
||||||
|
*ebx = 0;
|
||||||
|
*ecx = 0;
|
||||||
|
*edx = 0;
|
||||||
|
if ((env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) && count == 0) {
|
||||||
|
*ebx = env->features[FEAT_24_0_EBX] | env->avx10_version;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0x40000000:
|
case 0x40000000:
|
||||||
/*
|
/*
|
||||||
* CPUID code in kvm_arch_init_vcpu() ignores stuff
|
* CPUID code in kvm_arch_init_vcpu() ignores stuff
|
||||||
@ -7010,6 +7099,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||||||
*edx = 0;
|
*edx = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x80000022:
|
||||||
|
*eax = *ebx = *ecx = *edx = 0;
|
||||||
|
/* AMD Extended Performance Monitoring and Debug */
|
||||||
|
if (kvm_enabled() && cpu->enable_pmu &&
|
||||||
|
(env->features[FEAT_8000_0022_EAX] & CPUID_8000_0022_EAX_PERFMON_V2)) {
|
||||||
|
*eax |= CPUID_8000_0022_EAX_PERFMON_V2;
|
||||||
|
*ebx |= kvm_arch_get_supported_cpuid(cs->kvm_state, index, count,
|
||||||
|
R_EBX) & 0xf;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0xC0000000:
|
case 0xC0000000:
|
||||||
*eax = env->cpuid_xlevel2;
|
*eax = env->cpuid_xlevel2;
|
||||||
*ebx = 0;
|
*ebx = 0;
|
||||||
@ -7043,8 +7142,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x80000021:
|
case 0x80000021:
|
||||||
|
*eax = *ebx = *ecx = *edx = 0;
|
||||||
*eax = env->features[FEAT_8000_0021_EAX];
|
*eax = env->features[FEAT_8000_0021_EAX];
|
||||||
*ebx = *ecx = *edx = 0;
|
*ebx = env->features[FEAT_8000_0021_EBX];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* reserved values: zero */
|
/* reserved values: zero */
|
||||||
@ -7067,6 +7167,23 @@ static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cpuid_has_xsave_feature(CPUX86State *env, const ExtSaveArea *esa)
|
||||||
|
{
|
||||||
|
if (!esa->size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->features[esa->feature] & esa->bits) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (esa->feature == FEAT_7_0_EBX && esa->bits == CPUID_7_0_EBX_AVX512F
|
||||||
|
&& (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void x86_cpu_reset_hold(Object *obj, ResetType type)
|
static void x86_cpu_reset_hold(Object *obj, ResetType type)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(obj);
|
CPUState *cs = CPU(obj);
|
||||||
@ -7175,7 +7292,7 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) {
|
if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (env->features[esa->feature] & esa->bits) {
|
if (cpuid_has_xsave_feature(env, esa)) {
|
||||||
xcr0 |= 1ull << i;
|
xcr0 |= 1ull << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7313,7 +7430,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu)
|
|||||||
mask = 0;
|
mask = 0;
|
||||||
for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
||||||
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
||||||
if (env->features[esa->feature] & esa->bits) {
|
if (cpuid_has_xsave_feature(env, esa)) {
|
||||||
mask |= (1ULL << i);
|
mask |= (1ULL << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7406,6 +7523,12 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|||||||
~env->user_features[w] &
|
~env->user_features[w] &
|
||||||
~feature_word_info[w].no_autoenable_flags;
|
~feature_word_info[w].no_autoenable_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) && !env->avx10_version) {
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
x86_cpu_get_supported_cpuid(0x24, 0, &eax, &ebx, &ecx, &edx);
|
||||||
|
env->avx10_version = ebx & 0xff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
|
for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
|
||||||
@ -7469,6 +7592,11 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|||||||
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F);
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Advanced Vector Extensions 10 (AVX10) requires CPUID[0x24] */
|
||||||
|
if (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) {
|
||||||
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x24);
|
||||||
|
}
|
||||||
|
|
||||||
/* SVM requires CPUID[0x8000000A] */
|
/* SVM requires CPUID[0x8000000A] */
|
||||||
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
|
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
|
||||||
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A);
|
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A);
|
||||||
@ -7512,13 +7640,17 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|||||||
* Finishes initialization of CPUID data, filters CPU feature
|
* Finishes initialization of CPUID data, filters CPU feature
|
||||||
* words based on host availability of each feature.
|
* words based on host availability of each feature.
|
||||||
*
|
*
|
||||||
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
|
* Returns: true if any flag is not supported by the host, false otherwise.
|
||||||
*/
|
*/
|
||||||
static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
|
static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose)
|
||||||
{
|
{
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
FeatureWord w;
|
FeatureWord w;
|
||||||
const char *prefix = NULL;
|
const char *prefix = NULL;
|
||||||
|
bool have_filtered_features;
|
||||||
|
|
||||||
|
uint32_t eax_0, ebx_0, ecx_0, edx_0;
|
||||||
|
uint32_t eax_1, ebx_1, ecx_1, edx_1;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
prefix = accel_uses_host_cpuid()
|
prefix = accel_uses_host_cpuid()
|
||||||
@ -7540,13 +7672,10 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
|
|||||||
*/
|
*/
|
||||||
if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
|
if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
|
||||||
kvm_enabled()) {
|
kvm_enabled()) {
|
||||||
uint32_t eax_0, ebx_0, ecx_0, edx_0_unused;
|
|
||||||
uint32_t eax_1, ebx_1, ecx_1_unused, edx_1_unused;
|
|
||||||
|
|
||||||
x86_cpu_get_supported_cpuid(0x14, 0,
|
x86_cpu_get_supported_cpuid(0x14, 0,
|
||||||
&eax_0, &ebx_0, &ecx_0, &edx_0_unused);
|
&eax_0, &ebx_0, &ecx_0, &edx_0);
|
||||||
x86_cpu_get_supported_cpuid(0x14, 1,
|
x86_cpu_get_supported_cpuid(0x14, 1,
|
||||||
&eax_1, &ebx_1, &ecx_1_unused, &edx_1_unused);
|
&eax_1, &ebx_1, &ecx_1, &edx_1);
|
||||||
|
|
||||||
if (!eax_0 ||
|
if (!eax_0 ||
|
||||||
((ebx_0 & INTEL_PT_MINIMAL_EBX) != INTEL_PT_MINIMAL_EBX) ||
|
((ebx_0 & INTEL_PT_MINIMAL_EBX) != INTEL_PT_MINIMAL_EBX) ||
|
||||||
@ -7566,6 +7695,28 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
|
|||||||
mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix);
|
mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_filtered_features = x86_cpu_have_filtered_features(cpu);
|
||||||
|
|
||||||
|
if (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) {
|
||||||
|
x86_cpu_get_supported_cpuid(0x24, 0,
|
||||||
|
&eax_0, &ebx_0, &ecx_0, &edx_0);
|
||||||
|
uint8_t version = ebx_0 & 0xff;
|
||||||
|
|
||||||
|
if (version < env->avx10_version) {
|
||||||
|
if (prefix) {
|
||||||
|
warn_report("%s: avx10.%d. Adjust to avx10.%d",
|
||||||
|
prefix, env->avx10_version, version);
|
||||||
|
}
|
||||||
|
env->avx10_version = version;
|
||||||
|
have_filtered_features = true;
|
||||||
|
}
|
||||||
|
} else if (env->avx10_version && prefix) {
|
||||||
|
warn_report("%s: avx10.%d.", prefix, env->avx10_version);
|
||||||
|
have_filtered_features = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return have_filtered_features;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x86_cpu_hyperv_realize(X86CPU *cpu)
|
static void x86_cpu_hyperv_realize(X86CPU *cpu)
|
||||||
@ -7663,14 +7814,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid);
|
if (x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid)) {
|
||||||
|
if (cpu->enforce_cpuid) {
|
||||||
if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) {
|
error_setg(&local_err,
|
||||||
error_setg(&local_err,
|
accel_uses_host_cpuid() ?
|
||||||
accel_uses_host_cpuid() ?
|
|
||||||
"Host doesn't support requested features" :
|
"Host doesn't support requested features" :
|
||||||
"TCG doesn't support requested features");
|
"TCG doesn't support requested features");
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
|
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
|
||||||
@ -7985,6 +8136,26 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc,
|
|||||||
|
|
||||||
static void x86_cpu_post_initfn(Object *obj)
|
static void x86_cpu_post_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
|
static bool first = true;
|
||||||
|
uint64_t supported_xcr0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
supported_xcr0 =
|
||||||
|
((uint64_t) x86_cpu_get_supported_feature_word(NULL, FEAT_XSAVE_XCR0_HI) << 32) |
|
||||||
|
x86_cpu_get_supported_feature_word(NULL, FEAT_XSAVE_XCR0_LO);
|
||||||
|
|
||||||
|
for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) {
|
||||||
|
ExtSaveArea *esa = &x86_ext_save_areas[i];
|
||||||
|
|
||||||
|
if (!(supported_xcr0 & (1 << i))) {
|
||||||
|
esa->size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
accel_cpu_instance_init(CPU(obj));
|
accel_cpu_instance_init(CPU(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8329,6 +8500,7 @@ static Property x86_cpu_properties[] = {
|
|||||||
DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0),
|
DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0),
|
||||||
DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0),
|
DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0),
|
||||||
DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0),
|
DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0),
|
||||||
|
DEFINE_PROP_UINT8("avx10-version", X86CPU, env.avx10_version, 0),
|
||||||
DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0),
|
DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0),
|
||||||
DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true),
|
DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true),
|
||||||
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor),
|
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor),
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "cpu-qom.h"
|
#include "cpu-qom.h"
|
||||||
#include "kvm/hyperv-proto.h"
|
#include "kvm/hyperv-proto.h"
|
||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
|
#include "exec/memop.h"
|
||||||
#include "hw/i386/topology.h"
|
#include "hw/i386/topology.h"
|
||||||
#include "qapi/qapi-types-common.h"
|
#include "qapi/qapi-types-common.h"
|
||||||
#include "qemu/cpu-float.h"
|
#include "qemu/cpu-float.h"
|
||||||
@ -634,6 +635,8 @@ typedef enum FeatureWord {
|
|||||||
FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */
|
FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */
|
||||||
FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */
|
FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */
|
||||||
FEAT_8000_0021_EAX, /* CPUID[8000_0021].EAX */
|
FEAT_8000_0021_EAX, /* CPUID[8000_0021].EAX */
|
||||||
|
FEAT_8000_0021_EBX, /* CPUID[8000_0021].EBX */
|
||||||
|
FEAT_8000_0022_EAX, /* CPUID[8000_0022].EAX */
|
||||||
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
|
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
|
||||||
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
|
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
|
||||||
FEAT_KVM_HINTS, /* CPUID[4000_0001].EDX */
|
FEAT_KVM_HINTS, /* CPUID[4000_0001].EDX */
|
||||||
@ -662,6 +665,7 @@ typedef enum FeatureWord {
|
|||||||
FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */
|
FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */
|
||||||
FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */
|
FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */
|
||||||
FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */
|
FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */
|
||||||
|
FEAT_24_0_EBX, /* CPUID[EAX=0x24,ECX=0].EBX */
|
||||||
FEATURE_WORDS,
|
FEATURE_WORDS,
|
||||||
} FeatureWord;
|
} FeatureWord;
|
||||||
|
|
||||||
@ -972,6 +976,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||||||
#define CPUID_7_1_EDX_AMX_COMPLEX (1U << 8)
|
#define CPUID_7_1_EDX_AMX_COMPLEX (1U << 8)
|
||||||
/* PREFETCHIT0/1 Instructions */
|
/* PREFETCHIT0/1 Instructions */
|
||||||
#define CPUID_7_1_EDX_PREFETCHITI (1U << 14)
|
#define CPUID_7_1_EDX_PREFETCHITI (1U << 14)
|
||||||
|
/* Support for Advanced Vector Extensions 10 */
|
||||||
|
#define CPUID_7_1_EDX_AVX10 (1U << 19)
|
||||||
/* Flexible return and event delivery (FRED) */
|
/* Flexible return and event delivery (FRED) */
|
||||||
#define CPUID_7_1_EAX_FRED (1U << 17)
|
#define CPUID_7_1_EAX_FRED (1U << 17)
|
||||||
/* Load into IA32_KERNEL_GS_BASE (LKGS) */
|
/* Load into IA32_KERNEL_GS_BASE (LKGS) */
|
||||||
@ -988,6 +994,17 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||||||
/* Packets which contain IP payload have LIP values */
|
/* Packets which contain IP payload have LIP values */
|
||||||
#define CPUID_14_0_ECX_LIP (1U << 31)
|
#define CPUID_14_0_ECX_LIP (1U << 31)
|
||||||
|
|
||||||
|
/* AVX10 128-bit vector support is present */
|
||||||
|
#define CPUID_24_0_EBX_AVX10_128 (1U << 16)
|
||||||
|
/* AVX10 256-bit vector support is present */
|
||||||
|
#define CPUID_24_0_EBX_AVX10_256 (1U << 17)
|
||||||
|
/* AVX10 512-bit vector support is present */
|
||||||
|
#define CPUID_24_0_EBX_AVX10_512 (1U << 18)
|
||||||
|
/* AVX10 vector length support mask */
|
||||||
|
#define CPUID_24_0_EBX_AVX10_VL_MASK (CPUID_24_0_EBX_AVX10_128 | \
|
||||||
|
CPUID_24_0_EBX_AVX10_256 | \
|
||||||
|
CPUID_24_0_EBX_AVX10_512)
|
||||||
|
|
||||||
/* RAS Features */
|
/* RAS Features */
|
||||||
#define CPUID_8000_0007_EBX_OVERFLOW_RECOV (1U << 0)
|
#define CPUID_8000_0007_EBX_OVERFLOW_RECOV (1U << 0)
|
||||||
#define CPUID_8000_0007_EBX_SUCCOR (1U << 1)
|
#define CPUID_8000_0007_EBX_SUCCOR (1U << 1)
|
||||||
@ -1014,13 +1031,32 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||||||
#define CPUID_8000_0008_EBX_AMD_PSFD (1U << 28)
|
#define CPUID_8000_0008_EBX_AMD_PSFD (1U << 28)
|
||||||
|
|
||||||
/* Processor ignores nested data breakpoints */
|
/* Processor ignores nested data breakpoints */
|
||||||
#define CPUID_8000_0021_EAX_No_NESTED_DATA_BP (1U << 0)
|
#define CPUID_8000_0021_EAX_NO_NESTED_DATA_BP (1U << 0)
|
||||||
/* LFENCE is always serializing */
|
/* LFENCE is always serializing */
|
||||||
#define CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING (1U << 2)
|
#define CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING (1U << 2)
|
||||||
/* Null Selector Clears Base */
|
/* Null Selector Clears Base */
|
||||||
#define CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE (1U << 6)
|
#define CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE (1U << 6)
|
||||||
/* Automatic IBRS */
|
/* Automatic IBRS */
|
||||||
#define CPUID_8000_0021_EAX_AUTO_IBRS (1U << 8)
|
#define CPUID_8000_0021_EAX_AUTO_IBRS (1U << 8)
|
||||||
|
/* Enhanced Return Address Predictor Scurity */
|
||||||
|
#define CPUID_8000_0021_EAX_ERAPS (1U << 24)
|
||||||
|
/* Selective Branch Predictor Barrier */
|
||||||
|
#define CPUID_8000_0021_EAX_SBPB (1U << 27)
|
||||||
|
/* IBPB includes branch type prediction flushing */
|
||||||
|
#define CPUID_8000_0021_EAX_IBPB_BRTYPE (1U << 28)
|
||||||
|
/* Not vulnerable to Speculative Return Stack Overflow */
|
||||||
|
#define CPUID_8000_0021_EAX_SRSO_NO (1U << 29)
|
||||||
|
/* Not vulnerable to SRSO at the user-kernel boundary */
|
||||||
|
#define CPUID_8000_0021_EAX_SRSO_USER_KERNEL_NO (1U << 30)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return Address Predictor size. RapSize x 8 is the minimum number of
|
||||||
|
* CALL instructions software needs to execute to flush the RAP.
|
||||||
|
*/
|
||||||
|
#define CPUID_8000_0021_EBX_RAPSIZE (8U << 16)
|
||||||
|
|
||||||
|
/* Performance Monitoring Version 2 */
|
||||||
|
#define CPUID_8000_0022_EAX_PERFMON_V2 (1U << 0)
|
||||||
|
|
||||||
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
|
||||||
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
#define CPUID_XSAVE_XSAVEC (1U << 1)
|
||||||
@ -1278,14 +1314,14 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||||||
* are only needed for conditional branches.
|
* are only needed for conditional branches.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
CC_OP_EFLAGS = 0, /* all cc are explicitly computed, CC_SRC = flags */
|
||||||
CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */
|
CC_OP_ADCX = 1, /* CC_DST = C, CC_SRC = rest. */
|
||||||
CC_OP_ADCX, /* CC_DST = C, CC_SRC = rest. */
|
CC_OP_ADOX = 2, /* CC_SRC2 = O, CC_SRC = rest. */
|
||||||
CC_OP_ADOX, /* CC_SRC2 = O, CC_SRC = rest. */
|
CC_OP_ADCOX = 3, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
|
||||||
CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
|
|
||||||
CC_OP_CLR, /* Z and P set, all other flags clear. */
|
|
||||||
|
|
||||||
CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
|
/* Low 2 bits = MemOp constant for the size */
|
||||||
|
#define CC_OP_FIRST_BWLQ CC_OP_MULB
|
||||||
|
CC_OP_MULB = 4, /* modify all flags, C, O = (CC_SRC != 0) */
|
||||||
CC_OP_MULW,
|
CC_OP_MULW,
|
||||||
CC_OP_MULL,
|
CC_OP_MULL,
|
||||||
CC_OP_MULQ,
|
CC_OP_MULQ,
|
||||||
@ -1355,10 +1391,24 @@ typedef enum {
|
|||||||
CC_OP_POPCNTL__,
|
CC_OP_POPCNTL__,
|
||||||
CC_OP_POPCNTQ__,
|
CC_OP_POPCNTQ__,
|
||||||
CC_OP_POPCNT = sizeof(target_ulong) == 8 ? CC_OP_POPCNTQ__ : CC_OP_POPCNTL__,
|
CC_OP_POPCNT = sizeof(target_ulong) == 8 ? CC_OP_POPCNTQ__ : CC_OP_POPCNTL__,
|
||||||
|
#define CC_OP_LAST_BWLQ CC_OP_POPCNTQ__
|
||||||
|
|
||||||
CC_OP_NB,
|
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||||
} CCOp;
|
} CCOp;
|
||||||
QEMU_BUILD_BUG_ON(CC_OP_NB >= 128);
|
|
||||||
|
/* See X86DecodedInsn.cc_op, using int8_t. */
|
||||||
|
QEMU_BUILD_BUG_ON(CC_OP_DYNAMIC > INT8_MAX);
|
||||||
|
|
||||||
|
static inline MemOp cc_op_size(CCOp op)
|
||||||
|
{
|
||||||
|
MemOp size = op & 3;
|
||||||
|
|
||||||
|
QEMU_BUILD_BUG_ON(CC_OP_FIRST_BWLQ & 3);
|
||||||
|
assert(op >= CC_OP_FIRST_BWLQ && op <= CC_OP_LAST_BWLQ);
|
||||||
|
assert(size <= MO_TL);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct SegmentCache {
|
typedef struct SegmentCache {
|
||||||
uint32_t selector;
|
uint32_t selector;
|
||||||
@ -1918,6 +1968,8 @@ typedef struct CPUArchState {
|
|||||||
uint32_t cpuid_vendor3;
|
uint32_t cpuid_vendor3;
|
||||||
uint32_t cpuid_version;
|
uint32_t cpuid_version;
|
||||||
FeatureWordArray features;
|
FeatureWordArray features;
|
||||||
|
/* AVX10 version */
|
||||||
|
uint8_t avx10_version;
|
||||||
/* Features that were explicitly enabled/disabled */
|
/* Features that were explicitly enabled/disabled */
|
||||||
FeatureWordArray user_features;
|
FeatureWordArray user_features;
|
||||||
uint32_t cpuid_model[12];
|
uint32_t cpuid_model[12];
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||||
DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||||
|
DEF_HELPER_FLAGS_3(cc_compute_nz, TCG_CALL_NO_RWG_SE, tl, tl, tl, int)
|
||||||
|
|
||||||
DEF_HELPER_3(write_eflags, void, env, tl, i32)
|
DEF_HELPER_3(write_eflags, void, env, tl, i32)
|
||||||
DEF_HELPER_1(read_eflags, tl, env)
|
DEF_HELPER_1(read_eflags, tl, env)
|
||||||
|
@ -42,7 +42,7 @@ static uint32_t host_cpu_phys_bits(void)
|
|||||||
return host_phys_bits;
|
return host_phys_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu)
|
static void host_cpu_adjust_phys_bits(X86CPU *cpu)
|
||||||
{
|
{
|
||||||
uint32_t host_phys_bits = host_cpu_phys_bits();
|
uint32_t host_phys_bits = host_cpu_phys_bits();
|
||||||
uint32_t phys_bits = cpu->phys_bits;
|
uint32_t phys_bits = cpu->phys_bits;
|
||||||
@ -66,7 +66,7 @@ static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return phys_bits;
|
cpu->phys_bits = phys_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool host_cpu_realizefn(CPUState *cs, Error **errp)
|
bool host_cpu_realizefn(CPUState *cs, Error **errp)
|
||||||
@ -75,17 +75,7 @@ bool host_cpu_realizefn(CPUState *cs, Error **errp)
|
|||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
|
||||||
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
||||||
uint32_t phys_bits = host_cpu_adjust_phys_bits(cpu);
|
host_cpu_adjust_phys_bits(cpu);
|
||||||
|
|
||||||
if (phys_bits &&
|
|
||||||
(phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
|
|
||||||
phys_bits < 32)) {
|
|
||||||
error_setg(errp, "phys-bits should be between 32 and %u "
|
|
||||||
" (but is %u)",
|
|
||||||
TARGET_PHYS_ADDR_SPACE_BITS, phys_bits);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cpu->phys_bits = phys_bits;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -21,28 +21,38 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/cpuid.h"
|
||||||
|
#include "host/cpuinfo.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
#include "vmx.h"
|
#include "vmx.h"
|
||||||
#include "sysemu/hvf.h"
|
#include "sysemu/hvf.h"
|
||||||
#include "hvf-i386.h"
|
#include "hvf-i386.h"
|
||||||
|
|
||||||
static bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr)
|
static bool cached_xcr0;
|
||||||
|
static uint64_t supported_xcr0;
|
||||||
|
|
||||||
|
static void cache_host_xcr0()
|
||||||
{
|
{
|
||||||
uint32_t xcrl, xcrh;
|
if (cached_xcr0) {
|
||||||
|
return;
|
||||||
if (cpuid_ecx & CPUID_EXT_OSXSAVE) {
|
|
||||||
/*
|
|
||||||
* The xgetbv instruction is not available to older versions of
|
|
||||||
* the assembler, so we encode the instruction manually.
|
|
||||||
*/
|
|
||||||
asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcrl), "=d" (xcrh) : "c" (idx));
|
|
||||||
|
|
||||||
*xcr = (((uint64_t)xcrh) << 32) | xcrl;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (cpuinfo & CPUINFO_OSXSAVE) {
|
||||||
|
uint64_t host_xcr0 = xgetbv_low(0);
|
||||||
|
|
||||||
|
/* Only show xcr0 bits corresponding to usable features. */
|
||||||
|
supported_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
|
||||||
|
XSTATE_SSE_MASK | XSTATE_YMM_MASK |
|
||||||
|
XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
|
||||||
|
XSTATE_Hi16_ZMM_MASK);
|
||||||
|
if ((supported_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK)) !=
|
||||||
|
(XSTATE_FP_MASK | XSTATE_SSE_MASK)) {
|
||||||
|
supported_xcr0 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_xcr0 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
||||||
@ -51,6 +61,7 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
|||||||
uint64_t cap;
|
uint64_t cap;
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
cache_host_xcr0();
|
||||||
host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
|
host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
switch (func) {
|
switch (func) {
|
||||||
@ -66,7 +77,8 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
|||||||
ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
|
ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
|
||||||
CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
|
CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
|
||||||
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
|
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
|
||||||
CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE |
|
CPUID_EXT_POPCNT | CPUID_EXT_AES |
|
||||||
|
(supported_xcr0 ? CPUID_EXT_XSAVE : 0) |
|
||||||
CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
|
CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
|
||||||
ecx |= CPUID_EXT_HYPERVISOR;
|
ecx |= CPUID_EXT_HYPERVISOR;
|
||||||
break;
|
break;
|
||||||
@ -107,16 +119,14 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
|||||||
eax = 0;
|
eax = 0;
|
||||||
break;
|
break;
|
||||||
case 0xD:
|
case 0xD:
|
||||||
|
if (!supported_xcr0 ||
|
||||||
|
(idx > 1 && !(supported_xcr0 & (1 << idx)))) {
|
||||||
|
eax = ebx = ecx = edx = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
uint64_t host_xcr0;
|
eax = supported_xcr0;
|
||||||
if (xgetbv(ecx, 0, &host_xcr0)) {
|
|
||||||
uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
|
|
||||||
XSTATE_SSE_MASK | XSTATE_YMM_MASK |
|
|
||||||
XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
|
|
||||||
XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
|
|
||||||
XSTATE_Hi16_ZMM_MASK);
|
|
||||||
eax &= supp_xcr0;
|
|
||||||
}
|
|
||||||
} else if (idx == 1) {
|
} else if (idx == 1) {
|
||||||
hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
|
hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
|
||||||
eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
|
eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
|
||||||
|
@ -143,10 +143,6 @@ static void kvm_cpu_xsave_init(void)
|
|||||||
if (!esa->size) {
|
if (!esa->size) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((x86_cpu_get_supported_feature_word(NULL, esa->feature) & esa->bits)
|
|
||||||
!= esa->bits) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx);
|
host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx);
|
||||||
if (eax != 0) {
|
if (eax != 0) {
|
||||||
assert(esa->size == eax);
|
assert(esa->size == eax);
|
||||||
|
@ -1923,7 +1923,8 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
|
|||||||
case 0x7:
|
case 0x7:
|
||||||
case 0x14:
|
case 0x14:
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
case 0x1e: {
|
case 0x1e:
|
||||||
|
case 0x24: {
|
||||||
uint32_t times;
|
uint32_t times;
|
||||||
|
|
||||||
c->function = i;
|
c->function = i;
|
||||||
|
@ -22,41 +22,6 @@
|
|||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "helper-tcg.h"
|
#include "helper-tcg.h"
|
||||||
|
|
||||||
const uint8_t parity_table[256] = {
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|
||||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SHIFT 0
|
#define SHIFT 0
|
||||||
#include "cc_helper_template.h.inc"
|
#include "cc_helper_template.h.inc"
|
||||||
#undef SHIFT
|
#undef SHIFT
|
||||||
@ -95,6 +60,19 @@ static target_ulong compute_all_adcox(target_ulong dst, target_ulong src1,
|
|||||||
return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O);
|
return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target_ulong helper_cc_compute_nz(target_ulong dst, target_ulong src1,
|
||||||
|
int op)
|
||||||
|
{
|
||||||
|
if (CC_OP_HAS_EFLAGS(op)) {
|
||||||
|
return ~src1 & CC_Z;
|
||||||
|
} else {
|
||||||
|
MemOp size = cc_op_size(op);
|
||||||
|
target_ulong mask = MAKE_64BIT_MASK(0, 8 << size);
|
||||||
|
|
||||||
|
return dst & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
|
target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
|
||||||
target_ulong src2, int op)
|
target_ulong src2, int op)
|
||||||
{
|
{
|
||||||
@ -104,8 +82,6 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
|
|||||||
|
|
||||||
case CC_OP_EFLAGS:
|
case CC_OP_EFLAGS:
|
||||||
return src1;
|
return src1;
|
||||||
case CC_OP_CLR:
|
|
||||||
return CC_Z | CC_P;
|
|
||||||
case CC_OP_POPCNT:
|
case CC_OP_POPCNT:
|
||||||
return dst ? 0 : CC_Z;
|
return dst ? 0 : CC_Z;
|
||||||
|
|
||||||
@ -243,7 +219,6 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
|
|||||||
case CC_OP_LOGICW:
|
case CC_OP_LOGICW:
|
||||||
case CC_OP_LOGICL:
|
case CC_OP_LOGICL:
|
||||||
case CC_OP_LOGICQ:
|
case CC_OP_LOGICQ:
|
||||||
case CC_OP_CLR:
|
|
||||||
case CC_OP_POPCNT:
|
case CC_OP_POPCNT:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -22,12 +22,17 @@
|
|||||||
#if DATA_BITS == 8
|
#if DATA_BITS == 8
|
||||||
#define SUFFIX b
|
#define SUFFIX b
|
||||||
#define DATA_TYPE uint8_t
|
#define DATA_TYPE uint8_t
|
||||||
|
#define WIDER_TYPE uint32_t
|
||||||
#elif DATA_BITS == 16
|
#elif DATA_BITS == 16
|
||||||
#define SUFFIX w
|
#define SUFFIX w
|
||||||
#define DATA_TYPE uint16_t
|
#define DATA_TYPE uint16_t
|
||||||
|
#define WIDER_TYPE uint32_t
|
||||||
#elif DATA_BITS == 32
|
#elif DATA_BITS == 32
|
||||||
#define SUFFIX l
|
#define SUFFIX l
|
||||||
#define DATA_TYPE uint32_t
|
#define DATA_TYPE uint32_t
|
||||||
|
#if HOST_LONG_BITS >= 64
|
||||||
|
#define WIDER_TYPE uint64_t
|
||||||
|
#endif
|
||||||
#elif DATA_BITS == 64
|
#elif DATA_BITS == 64
|
||||||
#define SUFFIX q
|
#define SUFFIX q
|
||||||
#define DATA_TYPE uint64_t
|
#define DATA_TYPE uint64_t
|
||||||
@ -39,18 +44,18 @@
|
|||||||
|
|
||||||
/* dynamic flags computation */
|
/* dynamic flags computation */
|
||||||
|
|
||||||
static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
DATA_TYPE src2 = dst - src1;
|
DATA_TYPE src2 = dst - src1;
|
||||||
|
|
||||||
cf = dst < src1;
|
cf = dst < src1;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & CC_A;
|
af = (dst ^ src1 ^ src2) & CC_A;
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
@ -58,39 +63,54 @@ static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
return dst < src1;
|
return dst < src1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
|
static uint32_t glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
|
||||||
DATA_TYPE src3)
|
DATA_TYPE src3)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
|
#ifdef WIDER_TYPE
|
||||||
|
WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3;
|
||||||
|
DATA_TYPE src2 = dst - src13;
|
||||||
|
|
||||||
|
cf = dst < src13;
|
||||||
|
#else
|
||||||
DATA_TYPE src2 = dst - src1 - src3;
|
DATA_TYPE src2 = dst - src1 - src3;
|
||||||
|
|
||||||
cf = (src3 ? dst <= src1 : dst < src1);
|
cf = (src3 ? dst <= src1 : dst < src1);
|
||||||
pf = parity_table[(uint8_t)dst];
|
#endif
|
||||||
|
|
||||||
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & 0x10;
|
af = (dst ^ src1 ^ src2) & 0x10;
|
||||||
zf = (dst == 0) << 6;
|
zf = (dst == 0) << 6;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
|
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
|
||||||
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
|
static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
|
||||||
DATA_TYPE src3)
|
DATA_TYPE src3)
|
||||||
{
|
{
|
||||||
|
#ifdef WIDER_TYPE
|
||||||
|
WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3;
|
||||||
|
|
||||||
|
return dst < src13;
|
||||||
|
#else
|
||||||
return src3 ? dst <= src1 : dst < src1;
|
return src3 ? dst <= src1 : dst < src1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
|
static uint32_t glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
DATA_TYPE src1 = dst + src2;
|
DATA_TYPE src1 = dst + src2;
|
||||||
|
|
||||||
cf = src1 < src2;
|
cf = src1 < src2;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & CC_A;
|
af = (dst ^ src1 ^ src2) & CC_A;
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
|
static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
|
||||||
@ -100,86 +120,102 @@ static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
|
|||||||
return src1 < src2;
|
return src1 < src2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
|
static uint32_t glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
|
||||||
DATA_TYPE src3)
|
DATA_TYPE src3)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
|
#ifdef WIDER_TYPE
|
||||||
|
WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3;
|
||||||
|
DATA_TYPE src1 = dst + src23;
|
||||||
|
|
||||||
|
cf = src1 < src23;
|
||||||
|
#else
|
||||||
DATA_TYPE src1 = dst + src2 + src3;
|
DATA_TYPE src1 = dst + src2 + src3;
|
||||||
|
|
||||||
cf = (src3 ? src1 <= src2 : src1 < src2);
|
cf = (src3 ? src1 <= src2 : src1 < src2);
|
||||||
pf = parity_table[(uint8_t)dst];
|
#endif
|
||||||
|
|
||||||
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & 0x10;
|
af = (dst ^ src1 ^ src2) & 0x10;
|
||||||
zf = (dst == 0) << 6;
|
zf = (dst == 0) << 6;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
|
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
|
||||||
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
|
static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
|
||||||
DATA_TYPE src3)
|
DATA_TYPE src3)
|
||||||
{
|
{
|
||||||
|
#ifdef WIDER_TYPE
|
||||||
|
WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3;
|
||||||
|
DATA_TYPE src1 = dst + src23;
|
||||||
|
|
||||||
|
return src1 < src23;
|
||||||
|
#else
|
||||||
DATA_TYPE src1 = dst + src2 + src3;
|
DATA_TYPE src1 = dst + src2 + src3;
|
||||||
|
|
||||||
return (src3 ? src1 <= src2 : src1 < src2);
|
return (src3 ? src1 <= src2 : src1 < src2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = 0;
|
cf = 0;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = 0;
|
af = 0;
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = 0;
|
of = 0;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
DATA_TYPE src2;
|
DATA_TYPE src2;
|
||||||
|
|
||||||
cf = src1;
|
cf = src1;
|
||||||
src1 = dst - 1;
|
src1 = dst - 1;
|
||||||
src2 = 1;
|
src2 = 1;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & CC_A;
|
af = (dst ^ src1 ^ src2) & CC_A;
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = (dst == SIGN_MASK) * CC_O;
|
of = (dst == SIGN_MASK) * CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
DATA_TYPE src2;
|
DATA_TYPE src2;
|
||||||
|
|
||||||
cf = src1;
|
cf = src1;
|
||||||
src1 = dst + 1;
|
src1 = dst + 1;
|
||||||
src2 = 1;
|
src2 = 1;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = (dst ^ src1 ^ src2) & CC_A;
|
af = (dst ^ src1 ^ src2) & CC_A;
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = (dst == SIGN_MASK - 1) * CC_O;
|
of = (dst == SIGN_MASK - 1) * CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = (src1 >> (DATA_BITS - 1)) & CC_C;
|
cf = (src1 >> (DATA_BITS - 1)) & CC_C;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = 0; /* undefined */
|
af = 0; /* undefined */
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
/* of is defined iff shift count == 1 */
|
/* of is defined iff shift count == 1 */
|
||||||
of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
|
of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
@ -187,39 +223,39 @@ static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
return (src1 >> (DATA_BITS - 1)) & CC_C;
|
return (src1 >> (DATA_BITS - 1)) & CC_C;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = src1 & 1;
|
cf = src1 & 1;
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = 0; /* undefined */
|
af = 0; /* undefined */
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
/* of is defined iff shift count == 1 */
|
/* of is defined iff shift count == 1 */
|
||||||
of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
|
of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
|
/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
|
||||||
CF are modified and it is slower to do that. Note as well that we
|
CF are modified and it is slower to do that. Note as well that we
|
||||||
don't truncate SRC1 for computing carry to DATA_TYPE. */
|
don't truncate SRC1 for computing carry to DATA_TYPE. */
|
||||||
static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1)
|
static uint32_t glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = (src1 != 0);
|
cf = (src1 != 0);
|
||||||
pf = parity_table[(uint8_t)dst];
|
pf = compute_pf(dst);
|
||||||
af = 0; /* undefined */
|
af = 0; /* undefined */
|
||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = cf * CC_O;
|
of = cf * CC_O;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static uint32_t glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = (src1 == 0);
|
cf = (src1 == 0);
|
||||||
pf = 0; /* undefined */
|
pf = 0; /* undefined */
|
||||||
@ -227,7 +263,7 @@ static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = 0;
|
of = 0;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
@ -237,7 +273,7 @@ static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
|
|
||||||
static int glue(compute_all_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static int glue(compute_all_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
{
|
{
|
||||||
int cf, pf, af, zf, sf, of;
|
uint32_t cf, pf, af, zf, sf, of;
|
||||||
|
|
||||||
cf = (src1 != 0);
|
cf = (src1 != 0);
|
||||||
pf = 0; /* undefined */
|
pf = 0; /* undefined */
|
||||||
@ -245,7 +281,7 @@ static int glue(compute_all_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
zf = (dst == 0) * CC_Z;
|
zf = (dst == 0) * CC_Z;
|
||||||
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
|
||||||
of = 0;
|
of = 0;
|
||||||
return cf | pf | af | zf | sf | of;
|
return cf + pf + af + zf + sf + of;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
||||||
@ -258,3 +294,4 @@ static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
|
|||||||
#undef DATA_TYPE
|
#undef DATA_TYPE
|
||||||
#undef DATA_MASK
|
#undef DATA_MASK
|
||||||
#undef SUFFIX
|
#undef SUFFIX
|
||||||
|
#undef WIDER_TYPE
|
||||||
|
@ -345,9 +345,9 @@ static void decode_group15(DisasContext *s, CPUX86State *env, X86OpEntry *entry,
|
|||||||
[1] = X86_OP_ENTRYw(RDxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3),
|
[1] = X86_OP_ENTRYw(RDxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3),
|
||||||
[2] = X86_OP_ENTRYr(WRxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3 zextT0),
|
[2] = X86_OP_ENTRYr(WRxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3 zextT0),
|
||||||
[3] = X86_OP_ENTRYr(WRxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3 zextT0),
|
[3] = X86_OP_ENTRYr(WRxxBASE, R,y, cpuid(FSGSBASE) chk(o64) p_f3 zextT0),
|
||||||
[5] = X86_OP_ENTRY0(LFENCE, cpuid(SSE2) p_00),
|
[5] = X86_OP_ENTRY0(LFENCE, cpuid(SSE) p_00),
|
||||||
[6] = X86_OP_ENTRY0(MFENCE, cpuid(SSE2) p_00),
|
[6] = X86_OP_ENTRY0(MFENCE, cpuid(SSE2) p_00),
|
||||||
[7] = X86_OP_ENTRY0(SFENCE, cpuid(SSE2) p_00),
|
[7] = X86_OP_ENTRY0(SFENCE, cpuid(SSE) p_00),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const X86OpEntry group15_mem[8] = {
|
static const X86OpEntry group15_mem[8] = {
|
||||||
@ -2865,7 +2865,7 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
|
|||||||
tcg_gen_mov_i32(cpu_cc_op, decode.cc_op_dynamic);
|
tcg_gen_mov_i32(cpu_cc_op, decode.cc_op_dynamic);
|
||||||
}
|
}
|
||||||
set_cc_op(s, decode.cc_op);
|
set_cc_op(s, decode.cc_op);
|
||||||
cc_live = cc_op_live[decode.cc_op];
|
cc_live = cc_op_live(decode.cc_op);
|
||||||
} else {
|
} else {
|
||||||
cc_live = 0;
|
cc_live = 0;
|
||||||
}
|
}
|
||||||
|
@ -1452,19 +1452,12 @@ static void gen_bt_flags(DisasContext *s, X86DecodedInsn *decode, TCGv src, TCGv
|
|||||||
* C is the result of the test, Z is unchanged, and the others
|
* C is the result of the test, Z is unchanged, and the others
|
||||||
* are all undefined.
|
* are all undefined.
|
||||||
*/
|
*/
|
||||||
switch (s->cc_op) {
|
if (s->cc_op == CC_OP_DYNAMIC || CC_OP_HAS_EFLAGS(s->cc_op)) {
|
||||||
case CC_OP_DYNAMIC:
|
|
||||||
case CC_OP_CLR:
|
|
||||||
case CC_OP_EFLAGS:
|
|
||||||
case CC_OP_ADCX:
|
|
||||||
case CC_OP_ADOX:
|
|
||||||
case CC_OP_ADCOX:
|
|
||||||
/* Generate EFLAGS and replace the C bit. */
|
/* Generate EFLAGS and replace the C bit. */
|
||||||
cf = tcg_temp_new();
|
cf = tcg_temp_new();
|
||||||
tcg_gen_setcond_tl(TCG_COND_TSTNE, cf, src, mask);
|
tcg_gen_setcond_tl(TCG_COND_TSTNE, cf, src, mask);
|
||||||
prepare_update_cf(decode, s, cf);
|
prepare_update_cf(decode, s, cf);
|
||||||
break;
|
} else {
|
||||||
default:
|
|
||||||
/*
|
/*
|
||||||
* Z was going to be computed from the non-zero status of CC_DST.
|
* Z was going to be computed from the non-zero status of CC_DST.
|
||||||
* We can get that same Z value (and the new C value) by leaving
|
* We can get that same Z value (and the new C value) by leaving
|
||||||
@ -1473,9 +1466,8 @@ static void gen_bt_flags(DisasContext *s, X86DecodedInsn *decode, TCGv src, TCGv
|
|||||||
*/
|
*/
|
||||||
decode->cc_src = tcg_temp_new();
|
decode->cc_src = tcg_temp_new();
|
||||||
decode->cc_dst = cpu_cc_dst;
|
decode->cc_dst = cpu_cc_dst;
|
||||||
decode->cc_op = ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB;
|
decode->cc_op = CC_OP_SARB + cc_op_size(s->cc_op);
|
||||||
tcg_gen_shr_tl(decode->cc_src, src, s->T1);
|
tcg_gen_shr_tl(decode->cc_src, src, s->T1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3354,7 +3346,8 @@ static bool gen_eflags_adcox(DisasContext *s, X86DecodedInsn *decode, bool want_
|
|||||||
* bit, we might as well fish CF out of EFLAGS and save a shift.
|
* bit, we might as well fish CF out of EFLAGS and save a shift.
|
||||||
*/
|
*/
|
||||||
if (want_carry && (!need_flags || s->cc_op == CC_OP_SHLB + MO_TL)) {
|
if (want_carry && (!need_flags || s->cc_op == CC_OP_SHLB + MO_TL)) {
|
||||||
tcg_gen_shri_tl(decode->cc_dst, cpu_cc_src, (8 << (s->cc_op - CC_OP_SHLB)) - 1);
|
MemOp size = cc_op_size(s->cc_op);
|
||||||
|
tcg_gen_shri_tl(decode->cc_dst, cpu_cc_src, (8 << size) - 1);
|
||||||
got_cf = true;
|
got_cf = true;
|
||||||
}
|
}
|
||||||
gen_mov_eflags(s, decode->cc_src);
|
gen_mov_eflags(s, decode->cc_src);
|
||||||
@ -3784,13 +3777,13 @@ static void gen_shift_dynamic_flags(DisasContext *s, X86DecodedInsn *decode, TCG
|
|||||||
decode->cc_op_dynamic = tcg_temp_new_i32();
|
decode->cc_op_dynamic = tcg_temp_new_i32();
|
||||||
|
|
||||||
assert(decode->cc_dst == s->T0);
|
assert(decode->cc_dst == s->T0);
|
||||||
if (cc_op_live[s->cc_op] & USES_CC_DST) {
|
if (cc_op_live(s->cc_op) & USES_CC_DST) {
|
||||||
decode->cc_dst = tcg_temp_new();
|
decode->cc_dst = tcg_temp_new();
|
||||||
tcg_gen_movcond_tl(TCG_COND_EQ, decode->cc_dst, count, tcg_constant_tl(0),
|
tcg_gen_movcond_tl(TCG_COND_EQ, decode->cc_dst, count, tcg_constant_tl(0),
|
||||||
cpu_cc_dst, s->T0);
|
cpu_cc_dst, s->T0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cc_op_live[s->cc_op] & USES_CC_SRC) {
|
if (cc_op_live(s->cc_op) & USES_CC_SRC) {
|
||||||
tcg_gen_movcond_tl(TCG_COND_EQ, decode->cc_src, count, tcg_constant_tl(0),
|
tcg_gen_movcond_tl(TCG_COND_EQ, decode->cc_src, count, tcg_constant_tl(0),
|
||||||
cpu_cc_src, decode->cc_src);
|
cpu_cc_src, decode->cc_src);
|
||||||
}
|
}
|
||||||
@ -4724,7 +4717,8 @@ static void gen_XOR(DisasContext *s, X86DecodedInsn *decode)
|
|||||||
decode->op[2].unit == X86_OP_INT &&
|
decode->op[2].unit == X86_OP_INT &&
|
||||||
decode->op[1].n == decode->op[2].n) {
|
decode->op[1].n == decode->op[2].n) {
|
||||||
tcg_gen_movi_tl(s->T0, 0);
|
tcg_gen_movi_tl(s->T0, 0);
|
||||||
decode->cc_op = CC_OP_CLR;
|
decode->cc_op = CC_OP_EFLAGS;
|
||||||
|
decode->cc_src = tcg_constant_tl(CC_Z | CC_P);
|
||||||
} else {
|
} else {
|
||||||
MemOp ot = decode->op[1].ot;
|
MemOp ot = decode->op[1].ot;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define I386_HELPER_TCG_H
|
#define I386_HELPER_TCG_H
|
||||||
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
|
#include "qemu/host-utils.h"
|
||||||
|
|
||||||
/* Maximum instruction code size */
|
/* Maximum instruction code size */
|
||||||
#define TARGET_MAX_INSN_SIZE 16
|
#define TARGET_MAX_INSN_SIZE 16
|
||||||
@ -87,7 +88,10 @@ G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* cc_helper.c */
|
/* cc_helper.c */
|
||||||
extern const uint8_t parity_table[256];
|
static inline unsigned int compute_pf(uint8_t x)
|
||||||
|
{
|
||||||
|
return !parity8(x) * CC_P;
|
||||||
|
}
|
||||||
|
|
||||||
/* misc_helper.c */
|
/* misc_helper.c */
|
||||||
void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
|
void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
|
||||||
|
@ -237,7 +237,7 @@ void helper_daa(CPUX86State *env)
|
|||||||
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
|
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
|
||||||
/* well, speed is not an issue here, so we compute the flags by hand */
|
/* well, speed is not an issue here, so we compute the flags by hand */
|
||||||
eflags |= (al == 0) << 6; /* zf */
|
eflags |= (al == 0) << 6; /* zf */
|
||||||
eflags |= parity_table[al]; /* pf */
|
eflags |= compute_pf(al);
|
||||||
eflags |= (al & 0x80); /* sf */
|
eflags |= (al & 0x80); /* sf */
|
||||||
CC_SRC = eflags;
|
CC_SRC = eflags;
|
||||||
CC_OP = CC_OP_EFLAGS;
|
CC_OP = CC_OP_EFLAGS;
|
||||||
@ -269,7 +269,7 @@ void helper_das(CPUX86State *env)
|
|||||||
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
|
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
|
||||||
/* well, speed is not an issue here, so we compute the flags by hand */
|
/* well, speed is not an issue here, so we compute the flags by hand */
|
||||||
eflags |= (al == 0) << 6; /* zf */
|
eflags |= (al == 0) << 6; /* zf */
|
||||||
eflags |= parity_table[al]; /* pf */
|
eflags |= compute_pf(al);
|
||||||
eflags |= (al & 0x80); /* sf */
|
eflags |= (al & 0x80); /* sf */
|
||||||
CC_SRC = eflags;
|
CC_SRC = eflags;
|
||||||
CC_OP = CC_OP_EFLAGS;
|
CC_OP = CC_OP_EFLAGS;
|
||||||
|
@ -291,7 +291,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Bit set if the global variable is live after setting CC_OP to X. */
|
/* Bit set if the global variable is live after setting CC_OP to X. */
|
||||||
static const uint8_t cc_op_live[CC_OP_NB] = {
|
static const uint8_t cc_op_live_[] = {
|
||||||
[CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
|
[CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
|
||||||
[CC_OP_EFLAGS] = USES_CC_SRC,
|
[CC_OP_EFLAGS] = USES_CC_SRC,
|
||||||
[CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC,
|
[CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC,
|
||||||
@ -309,10 +309,24 @@ static const uint8_t cc_op_live[CC_OP_NB] = {
|
|||||||
[CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC,
|
[CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC,
|
||||||
[CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
|
[CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
|
||||||
[CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
|
[CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
|
||||||
[CC_OP_CLR] = 0,
|
|
||||||
[CC_OP_POPCNT] = USES_CC_DST,
|
[CC_OP_POPCNT] = USES_CC_DST,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint8_t cc_op_live(CCOp op)
|
||||||
|
{
|
||||||
|
uint8_t result;
|
||||||
|
assert(op >= 0 && op < ARRAY_SIZE(cc_op_live_));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the array is fully populated. A zero entry would correspond
|
||||||
|
* to a fixed value of EFLAGS, which can be obtained with CC_OP_EFLAGS
|
||||||
|
* as well.
|
||||||
|
*/
|
||||||
|
result = cc_op_live_[op];
|
||||||
|
assert(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void set_cc_op_1(DisasContext *s, CCOp op, bool dirty)
|
static void set_cc_op_1(DisasContext *s, CCOp op, bool dirty)
|
||||||
{
|
{
|
||||||
int dead;
|
int dead;
|
||||||
@ -322,7 +336,7 @@ static void set_cc_op_1(DisasContext *s, CCOp op, bool dirty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Discard CC computation that will no longer be used. */
|
/* Discard CC computation that will no longer be used. */
|
||||||
dead = cc_op_live[s->cc_op] & ~cc_op_live[op];
|
dead = cc_op_live(s->cc_op) & ~cc_op_live(op);
|
||||||
if (dead & USES_CC_DST) {
|
if (dead & USES_CC_DST) {
|
||||||
tcg_gen_discard_tl(cpu_cc_dst);
|
tcg_gen_discard_tl(cpu_cc_dst);
|
||||||
}
|
}
|
||||||
@ -803,17 +817,13 @@ static void gen_mov_eflags(DisasContext *s, TCGv reg)
|
|||||||
tcg_gen_mov_tl(reg, cpu_cc_src);
|
tcg_gen_mov_tl(reg, cpu_cc_src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (s->cc_op == CC_OP_CLR) {
|
|
||||||
tcg_gen_movi_tl(reg, CC_Z | CC_P);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = cpu_cc_dst;
|
dst = cpu_cc_dst;
|
||||||
src1 = cpu_cc_src;
|
src1 = cpu_cc_src;
|
||||||
src2 = cpu_cc_src2;
|
src2 = cpu_cc_src2;
|
||||||
|
|
||||||
/* Take care to not read values that are not live. */
|
/* Take care to not read values that are not live. */
|
||||||
live = cc_op_live[s->cc_op] & ~USES_CC_SRCT;
|
live = cc_op_live(s->cc_op) & ~USES_CC_SRCT;
|
||||||
dead = live ^ (USES_CC_DST | USES_CC_SRC | USES_CC_SRC2);
|
dead = live ^ (USES_CC_DST | USES_CC_SRC | USES_CC_SRC2);
|
||||||
if (dead) {
|
if (dead) {
|
||||||
TCGv zero = tcg_constant_tl(0);
|
TCGv zero = tcg_constant_tl(0);
|
||||||
@ -883,21 +893,20 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
|||||||
case CC_OP_SUBB ... CC_OP_SUBQ:
|
case CC_OP_SUBB ... CC_OP_SUBQ:
|
||||||
/* (DATA_TYPE)CC_SRCT < (DATA_TYPE)CC_SRC */
|
/* (DATA_TYPE)CC_SRCT < (DATA_TYPE)CC_SRC */
|
||||||
size = s->cc_op - CC_OP_SUBB;
|
size = s->cc_op - CC_OP_SUBB;
|
||||||
gen_ext_tl(s->cc_srcT, s->cc_srcT, size, false);
|
tcg_gen_ext_tl(s->cc_srcT, s->cc_srcT, size);
|
||||||
gen_ext_tl(cpu_cc_src, cpu_cc_src, size, false);
|
tcg_gen_ext_tl(cpu_cc_src, cpu_cc_src, size);
|
||||||
return (CCPrepare) { .cond = TCG_COND_LTU, .reg = s->cc_srcT,
|
return (CCPrepare) { .cond = TCG_COND_LTU, .reg = s->cc_srcT,
|
||||||
.reg2 = cpu_cc_src, .use_reg2 = true };
|
.reg2 = cpu_cc_src, .use_reg2 = true };
|
||||||
|
|
||||||
case CC_OP_ADDB ... CC_OP_ADDQ:
|
case CC_OP_ADDB ... CC_OP_ADDQ:
|
||||||
/* (DATA_TYPE)CC_DST < (DATA_TYPE)CC_SRC */
|
/* (DATA_TYPE)CC_DST < (DATA_TYPE)CC_SRC */
|
||||||
size = s->cc_op - CC_OP_ADDB;
|
size = cc_op_size(s->cc_op);
|
||||||
gen_ext_tl(cpu_cc_dst, cpu_cc_dst, size, false);
|
tcg_gen_ext_tl(cpu_cc_dst, cpu_cc_dst, size);
|
||||||
gen_ext_tl(cpu_cc_src, cpu_cc_src, size, false);
|
tcg_gen_ext_tl(cpu_cc_src, cpu_cc_src, size);
|
||||||
return (CCPrepare) { .cond = TCG_COND_LTU, .reg = cpu_cc_dst,
|
return (CCPrepare) { .cond = TCG_COND_LTU, .reg = cpu_cc_dst,
|
||||||
.reg2 = cpu_cc_src, .use_reg2 = true };
|
.reg2 = cpu_cc_src, .use_reg2 = true };
|
||||||
|
|
||||||
case CC_OP_LOGICB ... CC_OP_LOGICQ:
|
case CC_OP_LOGICB ... CC_OP_LOGICQ:
|
||||||
case CC_OP_CLR:
|
|
||||||
case CC_OP_POPCNT:
|
case CC_OP_POPCNT:
|
||||||
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
||||||
|
|
||||||
@ -908,7 +917,7 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
|||||||
|
|
||||||
case CC_OP_SHLB ... CC_OP_SHLQ:
|
case CC_OP_SHLB ... CC_OP_SHLQ:
|
||||||
/* (CC_SRC >> (DATA_BITS - 1)) & 1 */
|
/* (CC_SRC >> (DATA_BITS - 1)) & 1 */
|
||||||
size = s->cc_op - CC_OP_SHLB;
|
size = cc_op_size(s->cc_op);
|
||||||
return gen_prepare_sign_nz(cpu_cc_src, size);
|
return gen_prepare_sign_nz(cpu_cc_src, size);
|
||||||
|
|
||||||
case CC_OP_MULB ... CC_OP_MULQ:
|
case CC_OP_MULB ... CC_OP_MULQ:
|
||||||
@ -916,11 +925,11 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
|||||||
.reg = cpu_cc_src };
|
.reg = cpu_cc_src };
|
||||||
|
|
||||||
case CC_OP_BMILGB ... CC_OP_BMILGQ:
|
case CC_OP_BMILGB ... CC_OP_BMILGQ:
|
||||||
size = s->cc_op - CC_OP_BMILGB;
|
size = cc_op_size(s->cc_op);
|
||||||
return gen_prepare_val_nz(cpu_cc_src, size, true);
|
return gen_prepare_val_nz(cpu_cc_src, size, true);
|
||||||
|
|
||||||
case CC_OP_BLSIB ... CC_OP_BLSIQ:
|
case CC_OP_BLSIB ... CC_OP_BLSIQ:
|
||||||
size = s->cc_op - CC_OP_BLSIB;
|
size = cc_op_size(s->cc_op);
|
||||||
return gen_prepare_val_nz(cpu_cc_src, size, false);
|
return gen_prepare_val_nz(cpu_cc_src, size, false);
|
||||||
|
|
||||||
case CC_OP_ADCX:
|
case CC_OP_ADCX:
|
||||||
@ -969,14 +978,10 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
|
|||||||
case CC_OP_ADCOX:
|
case CC_OP_ADCOX:
|
||||||
return (CCPrepare) { .cond = TCG_COND_TSTNE, .reg = cpu_cc_src,
|
return (CCPrepare) { .cond = TCG_COND_TSTNE, .reg = cpu_cc_src,
|
||||||
.imm = CC_S };
|
.imm = CC_S };
|
||||||
case CC_OP_CLR:
|
|
||||||
case CC_OP_POPCNT:
|
case CC_OP_POPCNT:
|
||||||
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
||||||
default:
|
default:
|
||||||
{
|
return gen_prepare_sign_nz(cpu_cc_dst, cc_op_size(s->cc_op));
|
||||||
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
|
||||||
return gen_prepare_sign_nz(cpu_cc_dst, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -988,7 +993,7 @@ static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
|
|||||||
case CC_OP_ADCOX:
|
case CC_OP_ADCOX:
|
||||||
return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2,
|
return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2,
|
||||||
.no_setcond = true };
|
.no_setcond = true };
|
||||||
case CC_OP_CLR:
|
case CC_OP_LOGICB ... CC_OP_LOGICQ:
|
||||||
case CC_OP_POPCNT:
|
case CC_OP_POPCNT:
|
||||||
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
return (CCPrepare) { .cond = TCG_COND_NEVER };
|
||||||
case CC_OP_MULB ... CC_OP_MULQ:
|
case CC_OP_MULB ... CC_OP_MULQ:
|
||||||
@ -1004,20 +1009,24 @@ static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
|
|||||||
static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
|
static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
|
||||||
{
|
{
|
||||||
switch (s->cc_op) {
|
switch (s->cc_op) {
|
||||||
case CC_OP_DYNAMIC:
|
|
||||||
gen_compute_eflags(s);
|
|
||||||
/* FALLTHRU */
|
|
||||||
case CC_OP_EFLAGS:
|
case CC_OP_EFLAGS:
|
||||||
case CC_OP_ADCX:
|
case CC_OP_ADCX:
|
||||||
case CC_OP_ADOX:
|
case CC_OP_ADOX:
|
||||||
case CC_OP_ADCOX:
|
case CC_OP_ADCOX:
|
||||||
return (CCPrepare) { .cond = TCG_COND_TSTNE, .reg = cpu_cc_src,
|
return (CCPrepare) { .cond = TCG_COND_TSTNE, .reg = cpu_cc_src,
|
||||||
.imm = CC_Z };
|
.imm = CC_Z };
|
||||||
case CC_OP_CLR:
|
case CC_OP_DYNAMIC:
|
||||||
return (CCPrepare) { .cond = TCG_COND_ALWAYS };
|
gen_update_cc_op(s);
|
||||||
|
if (!reg) {
|
||||||
|
reg = tcg_temp_new();
|
||||||
|
}
|
||||||
|
gen_helper_cc_compute_nz(reg, cpu_cc_dst, cpu_cc_src, cpu_cc_op);
|
||||||
|
return (CCPrepare) { .cond = TCG_COND_EQ, .reg = reg, .imm = 0 };
|
||||||
|
case CC_OP_POPCNT:
|
||||||
|
return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_dst };
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
MemOp size = cc_op_size(s->cc_op);
|
||||||
return gen_prepare_val_nz(cpu_cc_dst, size, true);
|
return gen_prepare_val_nz(cpu_cc_dst, size, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1038,11 +1047,11 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
|
|||||||
switch (s->cc_op) {
|
switch (s->cc_op) {
|
||||||
case CC_OP_SUBB ... CC_OP_SUBQ:
|
case CC_OP_SUBB ... CC_OP_SUBQ:
|
||||||
/* We optimize relational operators for the cmp/jcc case. */
|
/* We optimize relational operators for the cmp/jcc case. */
|
||||||
size = s->cc_op - CC_OP_SUBB;
|
size = cc_op_size(s->cc_op);
|
||||||
switch (jcc_op) {
|
switch (jcc_op) {
|
||||||
case JCC_BE:
|
case JCC_BE:
|
||||||
gen_ext_tl(s->cc_srcT, s->cc_srcT, size, false);
|
tcg_gen_ext_tl(s->cc_srcT, s->cc_srcT, size);
|
||||||
gen_ext_tl(cpu_cc_src, cpu_cc_src, size, false);
|
tcg_gen_ext_tl(cpu_cc_src, cpu_cc_src, size);
|
||||||
cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = s->cc_srcT,
|
cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = s->cc_srcT,
|
||||||
.reg2 = cpu_cc_src, .use_reg2 = true };
|
.reg2 = cpu_cc_src, .use_reg2 = true };
|
||||||
break;
|
break;
|
||||||
@ -1052,8 +1061,8 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
|
|||||||
case JCC_LE:
|
case JCC_LE:
|
||||||
cond = TCG_COND_LE;
|
cond = TCG_COND_LE;
|
||||||
fast_jcc_l:
|
fast_jcc_l:
|
||||||
gen_ext_tl(s->cc_srcT, s->cc_srcT, size, true);
|
tcg_gen_ext_tl(s->cc_srcT, s->cc_srcT, size | MO_SIGN);
|
||||||
gen_ext_tl(cpu_cc_src, cpu_cc_src, size, true);
|
tcg_gen_ext_tl(cpu_cc_src, cpu_cc_src, size | MO_SIGN);
|
||||||
cc = (CCPrepare) { .cond = cond, .reg = s->cc_srcT,
|
cc = (CCPrepare) { .cond = cond, .reg = s->cc_srcT,
|
||||||
.reg2 = cpu_cc_src, .use_reg2 = true };
|
.reg2 = cpu_cc_src, .use_reg2 = true };
|
||||||
break;
|
break;
|
||||||
@ -1063,6 +1072,28 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CC_OP_LOGICB ... CC_OP_LOGICQ:
|
||||||
|
/* Mostly used for test+jump */
|
||||||
|
size = s->cc_op - CC_OP_LOGICB;
|
||||||
|
switch (jcc_op) {
|
||||||
|
case JCC_BE:
|
||||||
|
/* CF = 0, becomes jz/je */
|
||||||
|
jcc_op = JCC_Z;
|
||||||
|
goto slow_jcc;
|
||||||
|
case JCC_L:
|
||||||
|
/* OF = 0, becomes js/jns */
|
||||||
|
jcc_op = JCC_S;
|
||||||
|
goto slow_jcc;
|
||||||
|
case JCC_LE:
|
||||||
|
/* SF or ZF, becomes signed <= 0 */
|
||||||
|
tcg_gen_ext_tl(cpu_cc_dst, cpu_cc_dst, size | MO_SIGN);
|
||||||
|
cc = (CCPrepare) { .cond = TCG_COND_LE, .reg = cpu_cc_dst };
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto slow_jcc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
slow_jcc:
|
slow_jcc:
|
||||||
/* This actually generates good code for JC, JZ and JS. */
|
/* This actually generates good code for JC, JZ and JS. */
|
||||||
@ -1162,6 +1193,10 @@ static inline void gen_jcc1(DisasContext *s, int b, TCGLabel *l1)
|
|||||||
{
|
{
|
||||||
CCPrepare cc = gen_prepare_cc(s, b, NULL);
|
CCPrepare cc = gen_prepare_cc(s, b, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this must be _after_ gen_prepare_cc, because it
|
||||||
|
* can change the cc_op from CC_OP_DYNAMIC to CC_OP_EFLAGS!
|
||||||
|
*/
|
||||||
gen_update_cc_op(s);
|
gen_update_cc_op(s);
|
||||||
if (cc.use_reg2) {
|
if (cc.use_reg2) {
|
||||||
tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
|
tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
|
||||||
|
@ -45,6 +45,7 @@ RUN apk update && \
|
|||||||
libaio-dev \
|
libaio-dev \
|
||||||
libbpf-dev \
|
libbpf-dev \
|
||||||
libcap-ng-dev \
|
libcap-ng-dev \
|
||||||
|
libcbor-dev \
|
||||||
libdrm-dev \
|
libdrm-dev \
|
||||||
libepoxy-dev \
|
libepoxy-dev \
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
@ -90,6 +91,8 @@ RUN apk update && \
|
|||||||
py3-yaml \
|
py3-yaml \
|
||||||
python3 \
|
python3 \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rust \
|
||||||
|
rust-bindgen \
|
||||||
samurai \
|
samurai \
|
||||||
sdl2-dev \
|
sdl2-dev \
|
||||||
sdl2_image-dev \
|
sdl2_image-dev \
|
||||||
|
@ -16,6 +16,7 @@ RUN dnf distro-sync -y && \
|
|||||||
alsa-lib-devel \
|
alsa-lib-devel \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen-cli \
|
||||||
bison \
|
bison \
|
||||||
brlapi-devel \
|
brlapi-devel \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -102,6 +103,7 @@ RUN dnf distro-sync -y && \
|
|||||||
python3-sphinx_rtd_theme \
|
python3-sphinx_rtd_theme \
|
||||||
python3-tomli \
|
python3-tomli \
|
||||||
rdma-core-devel \
|
rdma-core-devel \
|
||||||
|
rust \
|
||||||
sed \
|
sed \
|
||||||
snappy-devel \
|
snappy-devel \
|
||||||
socat \
|
socat \
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:amd64 \
|
libcacard-dev:amd64 \
|
||||||
libcap-ng-dev:amd64 \
|
libcap-ng-dev:amd64 \
|
||||||
libcapstone-dev:amd64 \
|
libcapstone-dev:amd64 \
|
||||||
|
libcbor-dev:amd64 \
|
||||||
libcmocka-dev:amd64 \
|
libcmocka-dev:amd64 \
|
||||||
libcurl4-gnutls-dev:amd64 \
|
libcurl4-gnutls-dev:amd64 \
|
||||||
libdaxctl-dev:amd64 \
|
libdaxctl-dev:amd64 \
|
||||||
@ -170,6 +173,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/x86_64-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "x86_64-linux-gnu"
|
ENV ABI "x86_64-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=x86_64-linux-gnu"
|
ENV MESON_OPTS "--cross-file=x86_64-linux-gnu"
|
||||||
|
ENV RUST_TARGET "x86_64-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
|
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:arm64 \
|
libcacard-dev:arm64 \
|
||||||
libcap-ng-dev:arm64 \
|
libcap-ng-dev:arm64 \
|
||||||
libcapstone-dev:arm64 \
|
libcapstone-dev:arm64 \
|
||||||
|
libcbor-dev:arm64 \
|
||||||
libcmocka-dev:arm64 \
|
libcmocka-dev:arm64 \
|
||||||
libcurl4-gnutls-dev:arm64 \
|
libcurl4-gnutls-dev:arm64 \
|
||||||
libdaxctl-dev:arm64 \
|
libdaxctl-dev:arm64 \
|
||||||
@ -169,6 +172,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/aarch64-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "aarch64-linux-gnu"
|
ENV ABI "aarch64-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=aarch64-linux-gnu"
|
ENV MESON_OPTS "--cross-file=aarch64-linux-gnu"
|
||||||
|
ENV RUST_TARGET "aarch64-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST aarch64-softmmu,aarch64-linux-user
|
ENV DEF_TARGET_LIST aarch64-softmmu,aarch64-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:armhf \
|
libcacard-dev:armhf \
|
||||||
libcap-ng-dev:armhf \
|
libcap-ng-dev:armhf \
|
||||||
libcapstone-dev:armhf \
|
libcapstone-dev:armhf \
|
||||||
|
libcbor-dev:armhf \
|
||||||
libcmocka-dev:armhf \
|
libcmocka-dev:armhf \
|
||||||
libcurl4-gnutls-dev:armhf \
|
libcurl4-gnutls-dev:armhf \
|
||||||
libdaxctl-dev:armhf \
|
libdaxctl-dev:armhf \
|
||||||
@ -169,6 +172,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabihf && \
|
|||||||
|
|
||||||
ENV ABI "arm-linux-gnueabihf"
|
ENV ABI "arm-linux-gnueabihf"
|
||||||
ENV MESON_OPTS "--cross-file=arm-linux-gnueabihf"
|
ENV MESON_OPTS "--cross-file=arm-linux-gnueabihf"
|
||||||
|
ENV RUST_TARGET "armv7-unknown-linux-gnueabihf"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf-
|
||||||
ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user
|
ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:i386 \
|
libcacard-dev:i386 \
|
||||||
libcap-ng-dev:i386 \
|
libcap-ng-dev:i386 \
|
||||||
libcapstone-dev:i386 \
|
libcapstone-dev:i386 \
|
||||||
|
libcbor-dev:i386 \
|
||||||
libcmocka-dev:i386 \
|
libcmocka-dev:i386 \
|
||||||
libcurl4-gnutls-dev:i386 \
|
libcurl4-gnutls-dev:i386 \
|
||||||
libdaxctl-dev:i386 \
|
libdaxctl-dev:i386 \
|
||||||
@ -168,6 +171,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/i686-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "i686-linux-gnu"
|
ENV ABI "i686-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=i686-linux-gnu"
|
ENV MESON_OPTS "--cross-file=i686-linux-gnu"
|
||||||
|
ENV RUST_TARGET "i686-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
|
ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -91,6 +93,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:mips64el \
|
libcacard-dev:mips64el \
|
||||||
libcap-ng-dev:mips64el \
|
libcap-ng-dev:mips64el \
|
||||||
libcapstone-dev:mips64el \
|
libcapstone-dev:mips64el \
|
||||||
|
libcbor-dev:mips64el \
|
||||||
libcmocka-dev:mips64el \
|
libcmocka-dev:mips64el \
|
||||||
libcurl4-gnutls-dev:mips64el \
|
libcurl4-gnutls-dev:mips64el \
|
||||||
libdaxctl-dev:mips64el \
|
libdaxctl-dev:mips64el \
|
||||||
@ -158,6 +161,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 && \
|
|||||||
|
|
||||||
ENV ABI "mips64el-linux-gnuabi64"
|
ENV ABI "mips64el-linux-gnuabi64"
|
||||||
ENV MESON_OPTS "--cross-file=mips64el-linux-gnuabi64"
|
ENV MESON_OPTS "--cross-file=mips64el-linux-gnuabi64"
|
||||||
|
ENV RUST_TARGET "mips64el-unknown-linux-gnuabi64"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64-
|
||||||
ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user
|
ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -91,6 +93,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:mipsel \
|
libcacard-dev:mipsel \
|
||||||
libcap-ng-dev:mipsel \
|
libcap-ng-dev:mipsel \
|
||||||
libcapstone-dev:mipsel \
|
libcapstone-dev:mipsel \
|
||||||
|
libcbor-dev:mipsel \
|
||||||
libcmocka-dev:mipsel \
|
libcmocka-dev:mipsel \
|
||||||
libcurl4-gnutls-dev:mipsel \
|
libcurl4-gnutls-dev:mipsel \
|
||||||
libdaxctl-dev:mipsel \
|
libdaxctl-dev:mipsel \
|
||||||
@ -166,6 +169,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/mipsel-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "mipsel-linux-gnu"
|
ENV ABI "mipsel-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=mipsel-linux-gnu"
|
ENV MESON_OPTS "--cross-file=mipsel-linux-gnu"
|
||||||
|
ENV RUST_TARGET "mipsel-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST mipsel-softmmu,mipsel-linux-user
|
ENV DEF_TARGET_LIST mipsel-softmmu,mipsel-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:ppc64el \
|
libcacard-dev:ppc64el \
|
||||||
libcap-ng-dev:ppc64el \
|
libcap-ng-dev:ppc64el \
|
||||||
libcapstone-dev:ppc64el \
|
libcapstone-dev:ppc64el \
|
||||||
|
libcbor-dev:ppc64el \
|
||||||
libcmocka-dev:ppc64el \
|
libcmocka-dev:ppc64el \
|
||||||
libcurl4-gnutls-dev:ppc64el \
|
libcurl4-gnutls-dev:ppc64el \
|
||||||
libdaxctl-dev:ppc64el \
|
libdaxctl-dev:ppc64el \
|
||||||
@ -168,6 +171,7 @@ endian = 'little'\n" > /usr/local/share/meson/cross/powerpc64le-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "powerpc64le-linux-gnu"
|
ENV ABI "powerpc64le-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=powerpc64le-linux-gnu"
|
ENV MESON_OPTS "--cross-file=powerpc64le-linux-gnu"
|
||||||
|
ENV RUST_TARGET "powerpc64le-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user
|
ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -53,6 +54,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
@ -92,6 +94,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev:s390x \
|
libcacard-dev:s390x \
|
||||||
libcap-ng-dev:s390x \
|
libcap-ng-dev:s390x \
|
||||||
libcapstone-dev:s390x \
|
libcapstone-dev:s390x \
|
||||||
|
libcbor-dev:s390x \
|
||||||
libcmocka-dev:s390x \
|
libcmocka-dev:s390x \
|
||||||
libcurl4-gnutls-dev:s390x \
|
libcurl4-gnutls-dev:s390x \
|
||||||
libdaxctl-dev:s390x \
|
libdaxctl-dev:s390x \
|
||||||
@ -167,6 +170,7 @@ endian = 'big'\n" > /usr/local/share/meson/cross/s390x-linux-gnu && \
|
|||||||
|
|
||||||
ENV ABI "s390x-linux-gnu"
|
ENV ABI "s390x-linux-gnu"
|
||||||
ENV MESON_OPTS "--cross-file=s390x-linux-gnu"
|
ENV MESON_OPTS "--cross-file=s390x-linux-gnu"
|
||||||
|
ENV RUST_TARGET "s390x-unknown-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=s390x-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=s390x-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST s390x-softmmu,s390x-linux-user
|
ENV DEF_TARGET_LIST s390x-softmmu,s390x-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -41,6 +42,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev \
|
libcacard-dev \
|
||||||
libcap-ng-dev \
|
libcap-ng-dev \
|
||||||
libcapstone-dev \
|
libcapstone-dev \
|
||||||
|
libcbor-dev \
|
||||||
libcmocka-dev \
|
libcmocka-dev \
|
||||||
libcurl4-gnutls-dev \
|
libcurl4-gnutls-dev \
|
||||||
libdaxctl-dev \
|
libdaxctl-dev \
|
||||||
@ -120,6 +122,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
|
@ -23,6 +23,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
alsa-lib-devel \
|
alsa-lib-devel \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen-cli \
|
||||||
bison \
|
bison \
|
||||||
brlapi-devel \
|
brlapi-devel \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -61,6 +62,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
libbpf-devel \
|
libbpf-devel \
|
||||||
libcacard-devel \
|
libcacard-devel \
|
||||||
libcap-ng-devel \
|
libcap-ng-devel \
|
||||||
|
libcbor-devel \
|
||||||
libcmocka-devel \
|
libcmocka-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
libdrm-devel \
|
libdrm-devel \
|
||||||
@ -113,6 +115,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
python3-sphinx_rtd_theme \
|
python3-sphinx_rtd_theme \
|
||||||
python3-zombie-imp \
|
python3-zombie-imp \
|
||||||
rdma-core-devel \
|
rdma-core-devel \
|
||||||
|
rust \
|
||||||
sed \
|
sed \
|
||||||
snappy-devel \
|
snappy-devel \
|
||||||
socat \
|
socat \
|
||||||
|
@ -20,6 +20,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
nosync dnf install -y \
|
nosync dnf install -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen-cli \
|
||||||
bison \
|
bison \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
@ -53,6 +54,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
python3-sphinx \
|
python3-sphinx \
|
||||||
python3-sphinx_rtd_theme \
|
python3-sphinx_rtd_theme \
|
||||||
python3-zombie-imp \
|
python3-zombie-imp \
|
||||||
|
rust \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
|
@ -23,6 +23,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
alsa-lib-devel \
|
alsa-lib-devel \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen-cli \
|
||||||
bison \
|
bison \
|
||||||
brlapi-devel \
|
brlapi-devel \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -61,6 +62,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
libbpf-devel \
|
libbpf-devel \
|
||||||
libcacard-devel \
|
libcacard-devel \
|
||||||
libcap-ng-devel \
|
libcap-ng-devel \
|
||||||
|
libcbor-devel \
|
||||||
libcmocka-devel \
|
libcmocka-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
libdrm-devel \
|
libdrm-devel \
|
||||||
@ -113,6 +115,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
python3-sphinx_rtd_theme \
|
python3-sphinx_rtd_theme \
|
||||||
python3-zombie-imp \
|
python3-zombie-imp \
|
||||||
rdma-core-devel \
|
rdma-core-devel \
|
||||||
|
rust \
|
||||||
sed \
|
sed \
|
||||||
snappy-devel \
|
snappy-devel \
|
||||||
socat \
|
socat \
|
||||||
|
@ -47,6 +47,7 @@ RUN zypper update -y && \
|
|||||||
libbz2-devel \
|
libbz2-devel \
|
||||||
libcacard-devel \
|
libcacard-devel \
|
||||||
libcap-ng-devel \
|
libcap-ng-devel \
|
||||||
|
libcbor-devel \
|
||||||
libcmocka-devel \
|
libcmocka-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
libdrm-devel \
|
libdrm-devel \
|
||||||
@ -96,6 +97,8 @@ RUN zypper update -y && \
|
|||||||
python311-pip \
|
python311-pip \
|
||||||
python311-setuptools \
|
python311-setuptools \
|
||||||
rdma-core-devel \
|
rdma-core-devel \
|
||||||
|
rust \
|
||||||
|
rust-bindgen \
|
||||||
sed \
|
sed \
|
||||||
snappy-devel \
|
snappy-devel \
|
||||||
sndio-devel \
|
sndio-devel \
|
||||||
|
@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
eatmydata apt-get install --no-install-recommends -y \
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
bash \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
|
bindgen \
|
||||||
bison \
|
bison \
|
||||||
bsdextrautils \
|
bsdextrautils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
@ -41,6 +42,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
libcacard-dev \
|
libcacard-dev \
|
||||||
libcap-ng-dev \
|
libcap-ng-dev \
|
||||||
libcapstone-dev \
|
libcapstone-dev \
|
||||||
|
libcbor-dev \
|
||||||
libcmocka-dev \
|
libcmocka-dev \
|
||||||
libcurl4-gnutls-dev \
|
libcurl4-gnutls-dev \
|
||||||
libdaxctl-dev \
|
libdaxctl-dev \
|
||||||
@ -120,6 +122,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-yaml \
|
python3-yaml \
|
||||||
rpm2cpio \
|
rpm2cpio \
|
||||||
|
rustc \
|
||||||
sed \
|
sed \
|
||||||
socat \
|
socat \
|
||||||
sparse \
|
sparse \
|
||||||
|
@ -3,6 +3,7 @@ packages:
|
|||||||
- alsa
|
- alsa
|
||||||
- bash
|
- bash
|
||||||
- bc
|
- bc
|
||||||
|
- bindgen
|
||||||
- bison
|
- bison
|
||||||
- brlapi
|
- brlapi
|
||||||
- bzip2
|
- bzip2
|
||||||
@ -42,6 +43,7 @@ packages:
|
|||||||
- libc-static
|
- libc-static
|
||||||
- libcacard
|
- libcacard
|
||||||
- libcap-ng
|
- libcap-ng
|
||||||
|
- libcbor
|
||||||
- libcurl
|
- libcurl
|
||||||
- libdrm
|
- libdrm
|
||||||
- libepoxy
|
- libepoxy
|
||||||
@ -101,6 +103,7 @@ packages:
|
|||||||
- python3-tomli
|
- python3-tomli
|
||||||
- python3-venv
|
- python3-venv
|
||||||
- rpm2cpio
|
- rpm2cpio
|
||||||
|
- rust
|
||||||
- sdl2
|
- sdl2
|
||||||
- sdl2-image
|
- sdl2-image
|
||||||
- sed
|
- sed
|
||||||
|
@ -1648,7 +1648,8 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine),
|
|||||||
/* Ignore machines that cannot be used for qtests */
|
/* Ignore machines that cannot be used for qtests */
|
||||||
if (!strncmp("xenfv", machines[i].name, 5) ||
|
if (!strncmp("xenfv", machines[i].name, 5) ||
|
||||||
g_str_equal("xenpv", machines[i].name) ||
|
g_str_equal("xenpv", machines[i].name) ||
|
||||||
g_str_equal("xenpvh", machines[i].name)) {
|
g_str_equal("xenpvh", machines[i].name) ||
|
||||||
|
g_str_equal("nitro-enclave", machines[i].name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!skip_old_versioned ||
|
if (!skip_old_versioned ||
|
||||||
|
@ -61,6 +61,8 @@
|
|||||||
"py311-tomli",
|
"py311-tomli",
|
||||||
"python3",
|
"python3",
|
||||||
"rpm2cpio",
|
"rpm2cpio",
|
||||||
|
"rust",
|
||||||
|
"rust-bindgen-cli",
|
||||||
"sdl2",
|
"sdl2",
|
||||||
"sdl2_image",
|
"sdl2_image",
|
||||||
"snappy",
|
"snappy",
|
||||||
|
@ -35,6 +35,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
|
|||||||
__cpuid(1, a, b, c, d);
|
__cpuid(1, a, b, c, d);
|
||||||
|
|
||||||
info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
|
info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
|
||||||
|
info |= (c & bit_OSXSAVE ? CPUINFO_OSXSAVE : 0);
|
||||||
info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
|
info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
|
||||||
info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
|
info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
|
||||||
info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
|
info |= (c & bit_PCLMUL ? CPUINFO_PCLMUL : 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user