mirror of
https://github.com/Motorhead1991/qemu.git
synced 2026-01-06 14:37:42 -07:00
* rust: use native Meson support for clippy and rustdoc
* rust: add "bits", a custom bitflags implementation * target/i386: Remove FRED dependency on WRMSRNS * target/i386: Add the immediate form MSR access instruction support * TDX fixes -----BEGIN PGP SIGNATURE----- iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmg/XrsUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroOPIwf/VXh98Wd+7BJLkNJVFpczSF7YhJ5J a5BcWLOdVrzEJoqvfc9lkubgpShgzYDYJH99F/FloHddkPvZ1NRB2JXtDB1O3sSC NGaI4YM8uA/k21pt1jQtDJkk3Az7GNIBIcvi4HR5GjTOvOKGOXLpYErK52lM4GNG Aa17/Rb9Ug+QzyuS1M+mDPFdY2X6Hore2jXsp3ZH+U8hs+khecHEPsZUZ/Nlr1Z7 UoiYks4U29wtVJ/BCjNkgXoMJC6uqL/nOP5dLJBgboOodrtwdwpDMIUcyPLrOnjf ugJx0zYHIVdqpdft72EvLD92bzB8WoUiPsUA/dG45gGmhzuYWDmOqSdaKg== =l0gm -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * rust: use native Meson support for clippy and rustdoc * rust: add "bits", a custom bitflags implementation * target/i386: Remove FRED dependency on WRMSRNS * target/i386: Add the immediate form MSR access instruction support * TDX fixes # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmg/XrsUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOPIwf/VXh98Wd+7BJLkNJVFpczSF7YhJ5J # a5BcWLOdVrzEJoqvfc9lkubgpShgzYDYJH99F/FloHddkPvZ1NRB2JXtDB1O3sSC # NGaI4YM8uA/k21pt1jQtDJkk3Az7GNIBIcvi4HR5GjTOvOKGOXLpYErK52lM4GNG # Aa17/Rb9Ug+QzyuS1M+mDPFdY2X6Hore2jXsp3ZH+U8hs+khecHEPsZUZ/Nlr1Z7 # UoiYks4U29wtVJ/BCjNkgXoMJC6uqL/nOP5dLJBgboOodrtwdwpDMIUcyPLrOnjf # ugJx0zYHIVdqpdft72EvLD92bzB8WoUiPsUA/dG45gGmhzuYWDmOqSdaKg== # =l0gm # -----END PGP SIGNATURE----- # gpg: Signature made Tue 03 Jun 2025 16:44:43 EDT # 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' of https://gitlab.com/bonzini/qemu: rust: qemu-api-macros: add from_bits and into_bits to #[derive(TryInto)] rust: pl011: use the bits macro rust: add "bits", a custom bitflags implementation i386/tdvf: Fix build on 32-bit host i386/tdx: Fix build on 32-bit host meson: use config_base_arch for target libraries target/i386: Add the immediate form MSR access instruction support target/i386: Add a new CPU feature word for CPUID.7.1.ECX target/i386: Remove FRED dependency on WRMSRNS rust: use native Meson support for clippy and rustdoc rust: cell: remove support for running doctests with "cargo test --doc" rust: add qemu-api doctests to "meson test" build, dockerfiles: add support for detecting rustdoc rust: use "objects" for Rust executables as well meson: update to version 1.8.1 rust: bindings: allow ptr_offset_with_cast Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
f8a113701d
34 changed files with 934 additions and 149 deletions
|
|
@ -76,7 +76,8 @@
|
|||
fi
|
||||
- section_end buildenv
|
||||
- section_start test "Running tests"
|
||||
- $MAKE NINJA=":" $MAKE_CHECK_ARGS
|
||||
# doctests need all the compilation artifacts
|
||||
- $MAKE NINJA=":" MTESTARGS="--no-suite doc" $MAKE_CHECK_ARGS
|
||||
- section_end test
|
||||
|
||||
.native_test_job_template:
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ build-system-ubuntu:
|
|||
IMAGE: ubuntu2204
|
||||
CONFIGURE_ARGS: --enable-docs --enable-rust
|
||||
TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
MAKE_CHECK_ARGS: check-build check-doc
|
||||
|
||||
check-system-ubuntu:
|
||||
extends: .native_test_job_template
|
||||
|
|
@ -115,7 +115,7 @@ build-system-fedora:
|
|||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs --enable-crypto-afalg --enable-rust
|
||||
TARGETS: microblaze-softmmu mips-softmmu
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
MAKE_CHECK_ARGS: check-build check-doc
|
||||
|
||||
build-system-fedora-rust-nightly:
|
||||
extends:
|
||||
|
|
@ -127,12 +127,7 @@ build-system-fedora-rust-nightly:
|
|||
IMAGE: fedora-rust-nightly
|
||||
CONFIGURE_ARGS: --disable-docs --enable-rust --enable-strict-rust-lints
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
after_script:
|
||||
- source scripts/ci/gitlab-ci-section
|
||||
- section_start test "Running Rust doctests"
|
||||
- cd build
|
||||
- pyvenv/bin/meson devenv -w ../rust ${CARGO-cargo} test --doc -p qemu_api
|
||||
MAKE_CHECK_ARGS: check-build check-doc
|
||||
|
||||
allow_failure: true
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
doc-valid-idents = ["PrimeCell", ".."]
|
||||
doc-valid-idents = ["IrDA", "PrimeCell", ".."]
|
||||
allow-mixed-uninlined-format-args = false
|
||||
msrv = "1.77.0"
|
||||
16
configure
vendored
16
configure
vendored
|
|
@ -209,6 +209,8 @@ for opt do
|
|||
;;
|
||||
--rustc=*) RUSTC="$optarg"
|
||||
;;
|
||||
--rustdoc=*) RUSTDOC="$optarg"
|
||||
;;
|
||||
--cpu=*) cpu="$optarg"
|
||||
;;
|
||||
--extra-cflags=*)
|
||||
|
|
@ -323,6 +325,7 @@ pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
|||
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||
|
||||
rustc="${RUSTC-rustc}"
|
||||
rustdoc="${RUSTDOC-rustdoc}"
|
||||
|
||||
check_define() {
|
||||
cat > $TMPC <<EOF
|
||||
|
|
@ -660,6 +663,8 @@ for opt do
|
|||
;;
|
||||
--rustc=*)
|
||||
;;
|
||||
--rustdoc=*)
|
||||
;;
|
||||
--make=*)
|
||||
;;
|
||||
--install=*)
|
||||
|
|
@ -890,6 +895,7 @@ Advanced options (experts only):
|
|||
--cxx=CXX use C++ compiler CXX [$cxx]
|
||||
--objcc=OBJCC use Objective-C compiler OBJCC [$objcc]
|
||||
--rustc=RUSTC use Rust compiler RUSTC [$rustc]
|
||||
--rustdoc=RUSTDOC use rustdoc binary RUSTDOC [$rustdoc]
|
||||
--extra-cflags=CFLAGS append extra C compiler flags CFLAGS
|
||||
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
|
||||
--extra-objcflags=OBJCFLAGS append extra Objective C compiler flags OBJCFLAGS
|
||||
|
|
@ -1178,6 +1184,14 @@ fi
|
|||
##########################################
|
||||
# detect rust triple
|
||||
|
||||
meson_version=$($meson --version)
|
||||
if test "$rust" != disabled && ! version_ge "$meson_version" 1.8.1; then
|
||||
if test "$rust" = enabled; then
|
||||
error_exit "Rust support needs Meson 1.8.1 or newer"
|
||||
fi
|
||||
echo "Rust needs Meson 1.8.1, disabling" 2>&1
|
||||
rust=disabled
|
||||
fi
|
||||
if test "$rust" != disabled && has "$rustc" && $rustc -vV > "${TMPDIR1}/${TMPB}.out"; then
|
||||
rust_host_triple=$(sed -n 's/^host: //p' "${TMPDIR1}/${TMPB}.out")
|
||||
else
|
||||
|
|
@ -1893,8 +1907,10 @@ if test "$skip_meson" = no; then
|
|||
if test "$rust" != disabled; then
|
||||
if test "$rust_host_triple" != "$rust_target_triple"; then
|
||||
echo "rust = [$(meson_quote $rustc --target "$rust_target_triple")]" >> $cross
|
||||
echo "rustdoc = [$(meson_quote $rustdoc --target "$rust_target_triple")]" >> $cross
|
||||
else
|
||||
echo "rust = [$(meson_quote $rustc)]" >> $cross
|
||||
echo "rustdoc = [$(meson_quote $rustdoc)]" >> $cross
|
||||
fi
|
||||
fi
|
||||
echo "ar = [$(meson_quote $ar)]" >> $cross
|
||||
|
|
|
|||
|
|
@ -37,12 +37,16 @@ output directory (typically ``rust/target/``). A vanilla invocation
|
|||
of Cargo will complain that it cannot find the generated sources,
|
||||
which can be fixed in different ways:
|
||||
|
||||
* by using special shorthand targets in the QEMU build directory::
|
||||
* by using Makefile targets, provided by Meson, that run ``clippy`` or
|
||||
``rustdoc``:
|
||||
|
||||
make clippy
|
||||
make rustfmt
|
||||
make rustdoc
|
||||
|
||||
A target for ``rustfmt`` is also declared in ``rust/meson.build``:
|
||||
|
||||
make rustfmt
|
||||
|
||||
* by invoking ``cargo`` through the Meson `development environment`__
|
||||
feature::
|
||||
|
||||
|
|
@ -50,7 +54,7 @@ which can be fixed in different ways:
|
|||
pyvenv/bin/meson devenv -w ../rust cargo fmt
|
||||
|
||||
If you are going to use ``cargo`` repeatedly, ``pyvenv/bin/meson devenv``
|
||||
will enter a shell where commands like ``cargo clippy`` just work.
|
||||
will enter a shell where commands like ``cargo fmt`` just work.
|
||||
|
||||
__ https://mesonbuild.com/Commands.html#devenv
|
||||
|
||||
|
|
@ -66,7 +70,7 @@ be run via ``meson test`` or ``make``::
|
|||
|
||||
make check-rust
|
||||
|
||||
Building Rust code with ``--enable-modules`` is not supported yet.
|
||||
Note that doctests require all ``.o`` files from the build to be available.
|
||||
|
||||
Supported tools
|
||||
'''''''''''''''
|
||||
|
|
|
|||
|
|
@ -101,16 +101,16 @@ static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src,
|
|||
|
||||
/* sanity check */
|
||||
if (entry->size < entry->data_len) {
|
||||
error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%lx",
|
||||
error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%"PRIx64,
|
||||
entry->data_len, entry->size);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->address, TDVF_ALIGNMENT)) {
|
||||
error_report("MemoryAddress 0x%lx not page aligned", entry->address);
|
||||
error_report("MemoryAddress 0x%"PRIx64" not page aligned", entry->address);
|
||||
return -1;
|
||||
}
|
||||
if (!QEMU_IS_ALIGNED(entry->size, TDVF_ALIGNMENT)) {
|
||||
error_report("MemoryDataSize 0x%lx not page aligned", entry->size);
|
||||
error_report("MemoryDataSize 0x%"PRIx64" not page aligned", entry->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
11
meson.build
11
meson.build
|
|
@ -106,6 +106,7 @@ if have_rust
|
|||
endif
|
||||
|
||||
if have_rust
|
||||
rustdoc = find_program('rustdoc', required: get_option('rust'))
|
||||
bindgen = find_program('bindgen', required: get_option('rust'))
|
||||
if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
|
||||
if get_option('rust').enabled()
|
||||
|
|
@ -4134,13 +4135,12 @@ common_all = static_library('common',
|
|||
target_common_arch_libs = {}
|
||||
target_common_system_arch_libs = {}
|
||||
foreach target_base_arch, config_base_arch : config_base_arch_mak
|
||||
config_target = config_target_mak[target]
|
||||
target_inc = [include_directories('target' / target_base_arch)]
|
||||
inc = [common_user_inc + target_inc]
|
||||
|
||||
target_common = common_ss.apply(config_target, strict: false)
|
||||
target_system = system_ss.apply(config_target, strict: false)
|
||||
target_user = user_ss.apply(config_target, strict: false)
|
||||
target_common = common_ss.apply(config_base_arch, strict: false)
|
||||
target_system = system_ss.apply(config_base_arch, strict: false)
|
||||
target_user = user_ss.apply(config_base_arch, strict: false)
|
||||
common_deps = []
|
||||
system_deps = []
|
||||
user_deps = []
|
||||
|
|
@ -4403,7 +4403,7 @@ foreach target : target_dirs
|
|||
build_by_default: true,
|
||||
build_always_stale: true)
|
||||
rlib = static_library('rust_' + target.underscorify(),
|
||||
rlib_rs,
|
||||
structured_sources([], {'.': rlib_rs}),
|
||||
dependencies: target_rust.dependencies(),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'c')
|
||||
|
|
@ -4757,6 +4757,7 @@ if have_rust
|
|||
summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']}
|
||||
summary_info += {'rustc': ' '.join(rustc.cmd_array())}
|
||||
summary_info += {'rustc version': rustc.version()}
|
||||
summary_info += {'rustdoc': rustdoc}
|
||||
summary_info += {'bindgen': bindgen.full_path()}
|
||||
summary_info += {'bindgen version': bindgen.version()}
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ def main() -> int:
|
|||
parser.parse_args()
|
||||
|
||||
packages = {
|
||||
"meson==1.5.0":
|
||||
"52b34f4903b882df52ad0d533146d4b992c018ea77399f825579737672ae7b20",
|
||||
"meson==1.8.1":
|
||||
"374bbf71247e629475fc10b0bd2ef66fc418c2d8f4890572f74de0f97d0d42da",
|
||||
}
|
||||
|
||||
vendor_dir = Path(__file__, "..", "..", "wheels").resolve()
|
||||
|
|
|
|||
Binary file not shown.
BIN
python/wheels/meson-1.8.1-py3-none-any.whl
Normal file
BIN
python/wheels/meson-1.8.1-py3-none-any.whl
Normal file
Binary file not shown.
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
[meson]
|
||||
# The install key should match the version in python/wheels/
|
||||
meson = { accepted = ">=1.5.0", installed = "1.5.0", canary = "meson" }
|
||||
meson = { accepted = ">=1.5.0", installed = "1.8.1", canary = "meson" }
|
||||
pycotap = { accepted = ">=1.1.0", installed = "1.3.1" }
|
||||
|
||||
[docs]
|
||||
|
|
|
|||
8
rust/Cargo.lock
generated
8
rust/Cargo.lock
generated
|
|
@ -31,6 +31,13 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bits"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"qemu_api_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.12.0"
|
||||
|
|
@ -66,6 +73,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bilge",
|
||||
"bilge-impl",
|
||||
"bits",
|
||||
"qemu_api",
|
||||
"qemu_api_macros",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"bits",
|
||||
"qemu-api-macros",
|
||||
"qemu-api",
|
||||
"hw/char/pl011",
|
||||
|
|
@ -63,7 +64,6 @@ ignored_unit_patterns = "deny"
|
|||
implicit_clone = "deny"
|
||||
macro_use_imports = "deny"
|
||||
missing_safety_doc = "deny"
|
||||
multiple_crate_versions = "deny"
|
||||
mut_mut = "deny"
|
||||
needless_bitwise_bool = "deny"
|
||||
needless_pass_by_ref_mut = "deny"
|
||||
|
|
|
|||
19
rust/bits/Cargo.toml
Normal file
19
rust/bits/Cargo.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "bits"
|
||||
version = "0.1.0"
|
||||
authors = ["Paolo Bonzini <pbonzini@redhat.com>"]
|
||||
description = "const-friendly bit flags"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
qemu_api_macros = { path = "../qemu-api-macros" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
16
rust/bits/meson.build
Normal file
16
rust/bits/meson.build
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
_bits_rs = static_library(
|
||||
'bits',
|
||||
'src/lib.rs',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [qemu_api_macros],
|
||||
)
|
||||
|
||||
bits_rs = declare_dependency(link_with: _bits_rs)
|
||||
|
||||
rust.test('rust-bits-tests', _bits_rs,
|
||||
suite: ['unit', 'rust'])
|
||||
|
||||
rust.doctest('rust-bits-doctests', _bits_rs,
|
||||
dependencies: bits_rs,
|
||||
suite: ['doc', 'rust'])
|
||||
443
rust/bits/src/lib.rs
Normal file
443
rust/bits/src/lib.rs
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
// SPDX-License-Identifier: MIT or Apache-2.0 or GPL-2.0-or-later
|
||||
|
||||
/// # Definition entry point
|
||||
///
|
||||
/// Define a struct with a single field of type $type. Include public constants
|
||||
/// for each element listed in braces.
|
||||
///
|
||||
/// The unnamed element at the end, if present, can be used to enlarge the set
|
||||
/// of valid bits. Bits that are valid but not listed are treated normally for
|
||||
/// the purpose of arithmetic operations, and are printed with their hexadecimal
|
||||
/// value.
|
||||
///
|
||||
/// The struct implements the following traits: [`BitAnd`](std::ops::BitAnd),
|
||||
/// [`BitOr`](std::ops::BitOr), [`BitXor`](std::ops::BitXor),
|
||||
/// [`Not`](std::ops::Not), [`Sub`](std::ops::Sub); [`Debug`](std::fmt::Debug),
|
||||
/// [`Display`](std::fmt::Display), [`Binary`](std::fmt::Binary),
|
||||
/// [`Octal`](std::fmt::Octal), [`LowerHex`](std::fmt::LowerHex),
|
||||
/// [`UpperHex`](std::fmt::UpperHex); [`From`]`<type>`/[`Into`]`<type>` where
|
||||
/// type is the type specified in the definition.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bits::bits;
|
||||
/// bits! {
|
||||
/// pub struct Colors(u8) {
|
||||
/// BLACK = 0,
|
||||
/// RED = 1,
|
||||
/// GREEN = 1 << 1,
|
||||
/// BLUE = 1 << 2,
|
||||
/// WHITE = (1 << 0) | (1 << 1) | (1 << 2),
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use bits::bits;
|
||||
/// # bits! { pub struct Colors(u8) { BLACK = 0, RED = 1, GREEN = 1 << 1, BLUE = 1 << 2, } }
|
||||
///
|
||||
/// bits! {
|
||||
/// pub struct Colors8(u8) {
|
||||
/// BLACK = 0,
|
||||
/// RED = 1,
|
||||
/// GREEN = 1 << 1,
|
||||
/// BLUE = 1 << 2,
|
||||
/// WHITE = (1 << 0) | (1 << 1) | (1 << 2),
|
||||
///
|
||||
/// _ = 255,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // The previously defined struct ignores bits not explicitly defined.
|
||||
/// assert_eq!(
|
||||
/// Colors::from(255).into_bits(),
|
||||
/// (Colors::RED | Colors::GREEN | Colors::BLUE).into_bits()
|
||||
/// );
|
||||
///
|
||||
/// // Adding "_ = 255" makes it retain other bits as well.
|
||||
/// assert_eq!(Colors8::from(255).into_bits(), 255);
|
||||
///
|
||||
/// // all() does not include the additional bits, valid_bits() does
|
||||
/// assert_eq!(Colors8::all().into_bits(), Colors::all().into_bits());
|
||||
/// assert_eq!(Colors8::valid_bits().into_bits(), 255);
|
||||
/// ```
|
||||
///
|
||||
/// # Evaluation entry point
|
||||
///
|
||||
/// Return a constant corresponding to the boolean expression `$expr`.
|
||||
/// Identifiers in the expression correspond to values defined for the
|
||||
/// type `$type`. Supported operators are `!` (unary), `-`, `&`, `^`, `|`.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use bits::bits;
|
||||
/// bits! {
|
||||
/// pub struct Colors(u8) {
|
||||
/// BLACK = 0,
|
||||
/// RED = 1,
|
||||
/// GREEN = 1 << 1,
|
||||
/// BLUE = 1 << 2,
|
||||
/// // same as "WHITE = 7",
|
||||
/// WHITE = bits!(Self as u8: RED | GREEN | BLUE),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let rgb = bits! { Colors: RED | GREEN | BLUE };
|
||||
/// assert_eq!(rgb, Colors::WHITE);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! bits {
|
||||
{
|
||||
$(#[$struct_meta:meta])*
|
||||
$struct_vis:vis struct $struct_name:ident($field_vis:vis $type:ty) {
|
||||
$($(#[$const_meta:meta])* $const:ident = $val:expr),+
|
||||
$(,_ = $mask:expr)?
|
||||
$(,)?
|
||||
}
|
||||
} => {
|
||||
$(#[$struct_meta])*
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
$struct_vis struct $struct_name($field_vis $type);
|
||||
|
||||
impl $struct_name {
|
||||
$( #[allow(dead_code)] $(#[$const_meta])*
|
||||
pub const $const: $struct_name = $struct_name($val); )+
|
||||
|
||||
#[doc(hidden)]
|
||||
const VALID__: $type = $( Self::$const.0 )|+ $(|$mask)?;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn empty() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn all() -> Self {
|
||||
Self($( Self::$const.0 )|+)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn valid_bits() -> Self {
|
||||
Self(Self::VALID__)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn valid(val: $type) -> bool {
|
||||
(val & !Self::VALID__) == 0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn any_set(self, mask: Self) -> bool {
|
||||
(self.0 & mask.0) != 0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn all_set(self, mask: Self) -> bool {
|
||||
(self.0 & mask.0) == mask.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn none_set(self, mask: Self) -> bool {
|
||||
(self.0 & mask.0) == 0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn from_bits(value: $type) -> Self {
|
||||
$struct_name(value)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn into_bits(self) -> $type {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn set(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self, rhs: Self) {
|
||||
self.0 &= !rhs.0;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn toggle(&mut self, rhs: Self) {
|
||||
self.0 ^= rhs.0;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn intersection(self, rhs: Self) -> Self {
|
||||
$struct_name(self.0 & rhs.0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn difference(self, rhs: Self) -> Self {
|
||||
$struct_name(self.0 & !rhs.0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn symmetric_difference(self, rhs: Self) -> Self {
|
||||
$struct_name(self.0 ^ rhs.0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn union(self, rhs: Self) -> Self {
|
||||
$struct_name(self.0 | rhs.0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub const fn invert(self) -> Self {
|
||||
$struct_name(self.0 ^ Self::VALID__)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Binary for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
// If no width, use the highest valid bit
|
||||
let width = f.width().unwrap_or((Self::VALID__.ilog2() + 1) as usize);
|
||||
write!(f, "{:0>width$.precision$b}", self.0,
|
||||
width = width,
|
||||
precision = f.precision().unwrap_or(width))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::LowerHex for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
<$type as ::std::fmt::LowerHex>::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Octal for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
<$type as ::std::fmt::Octal>::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::UpperHex for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
<$type as ::std::fmt::UpperHex>::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "{}({})", stringify!($struct_name), self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for $struct_name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
use ::std::fmt::Display;
|
||||
let mut first = true;
|
||||
let mut left = self.0;
|
||||
$(if Self::$const.0.is_power_of_two() && (self & Self::$const).0 != 0 {
|
||||
if first { first = false } else { Display::fmt(&'|', f)?; }
|
||||
Display::fmt(stringify!($const), f)?;
|
||||
left -= Self::$const.0;
|
||||
})+
|
||||
if first {
|
||||
Display::fmt(&'0', f)
|
||||
} else if left != 0 {
|
||||
write!(f, "|{left:#x}")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::cmp::PartialEq<$type> for $struct_name {
|
||||
fn eq(&self, rhs: &$type) -> bool {
|
||||
self.0 == *rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitAnd<$struct_name> for &$struct_name {
|
||||
type Output = $struct_name;
|
||||
fn bitand(self, rhs: $struct_name) -> Self::Output {
|
||||
$struct_name(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitAndAssign<$struct_name> for $struct_name {
|
||||
fn bitand_assign(&mut self, rhs: $struct_name) {
|
||||
self.0 = self.0 & rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitXor<$struct_name> for &$struct_name {
|
||||
type Output = $struct_name;
|
||||
fn bitxor(self, rhs: $struct_name) -> Self::Output {
|
||||
$struct_name(self.0 ^ rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitXorAssign<$struct_name> for $struct_name {
|
||||
fn bitxor_assign(&mut self, rhs: $struct_name) {
|
||||
self.0 = self.0 ^ rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitOr<$struct_name> for &$struct_name {
|
||||
type Output = $struct_name;
|
||||
fn bitor(self, rhs: $struct_name) -> Self::Output {
|
||||
$struct_name(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitOrAssign<$struct_name> for $struct_name {
|
||||
fn bitor_assign(&mut self, rhs: $struct_name) {
|
||||
self.0 = self.0 | rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Sub<$struct_name> for &$struct_name {
|
||||
type Output = $struct_name;
|
||||
fn sub(self, rhs: $struct_name) -> Self::Output {
|
||||
$struct_name(self.0 & !rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::SubAssign<$struct_name> for $struct_name {
|
||||
fn sub_assign(&mut self, rhs: $struct_name) {
|
||||
self.0 = self.0 - rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Not for &$struct_name {
|
||||
type Output = $struct_name;
|
||||
fn not(self) -> Self::Output {
|
||||
$struct_name(self.0 ^ $struct_name::VALID__)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitAnd<$struct_name> for $struct_name {
|
||||
type Output = Self;
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
$struct_name(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitXor<$struct_name> for $struct_name {
|
||||
type Output = Self;
|
||||
fn bitxor(self, rhs: Self) -> Self::Output {
|
||||
$struct_name(self.0 ^ rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::BitOr<$struct_name> for $struct_name {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
$struct_name(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Sub<$struct_name> for $struct_name {
|
||||
type Output = Self;
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
$struct_name(self.0 & !rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Not for $struct_name {
|
||||
type Output = Self;
|
||||
fn not(self) -> Self::Output {
|
||||
$struct_name(self.0 ^ Self::VALID__)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$struct_name> for $type {
|
||||
fn from(x: $struct_name) -> $type {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$type> for $struct_name {
|
||||
fn from(x: $type) -> Self {
|
||||
$struct_name(x & Self::VALID__)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{ $type:ty: $expr:expr } => {
|
||||
::qemu_api_macros::bits_const_internal! { $type @ ($expr) }
|
||||
};
|
||||
|
||||
{ $type:ty as $int_type:ty: $expr:expr } => {
|
||||
(::qemu_api_macros::bits_const_internal! { $type @ ($expr) }.into_bits()) as $int_type
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
bits! {
|
||||
pub struct InterruptMask(u32) {
|
||||
OE = 1 << 10,
|
||||
BE = 1 << 9,
|
||||
PE = 1 << 8,
|
||||
FE = 1 << 7,
|
||||
RT = 1 << 6,
|
||||
TX = 1 << 5,
|
||||
RX = 1 << 4,
|
||||
DSR = 1 << 3,
|
||||
DCD = 1 << 2,
|
||||
CTS = 1 << 1,
|
||||
RI = 1 << 0,
|
||||
|
||||
E = bits!(Self as u32: OE | BE | PE | FE),
|
||||
MS = bits!(Self as u32: RI | DSR | DCD | CTS),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_not() {
|
||||
assert_eq!(
|
||||
!InterruptMask::from(InterruptMask::RT.0),
|
||||
InterruptMask::E | InterruptMask::MS | InterruptMask::TX | InterruptMask::RX
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_and() {
|
||||
assert_eq!(
|
||||
InterruptMask::from(0),
|
||||
InterruptMask::MS & InterruptMask::OE
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_or() {
|
||||
assert_eq!(
|
||||
InterruptMask::E,
|
||||
InterruptMask::OE | InterruptMask::BE | InterruptMask::PE | InterruptMask::FE
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_xor() {
|
||||
assert_eq!(
|
||||
InterruptMask::E ^ InterruptMask::BE,
|
||||
InterruptMask::OE | InterruptMask::PE | InterruptMask::FE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ crate-type = ["staticlib"]
|
|||
[dependencies]
|
||||
bilge = { version = "0.2.0" }
|
||||
bilge-impl = { version = "0.2.0" }
|
||||
bits = { path = "../../../bits" }
|
||||
qemu_api = { path = "../../../qemu-api" }
|
||||
qemu_api_macros = { path = "../../../qemu-api-macros" }
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ _libpl011_rs = static_library(
|
|||
dependencies: [
|
||||
bilge_rs,
|
||||
bilge_impl_rs,
|
||||
bits_rs,
|
||||
qemu_api,
|
||||
qemu_api_macros,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ pub struct PL011Registers {
|
|||
#[doc(alias = "cr")]
|
||||
pub control: registers::Control,
|
||||
pub dmacr: u32,
|
||||
pub int_enabled: u32,
|
||||
pub int_level: u32,
|
||||
pub int_enabled: Interrupt,
|
||||
pub int_level: Interrupt,
|
||||
pub read_fifo: Fifo,
|
||||
pub ilpr: u32,
|
||||
pub ibrd: u32,
|
||||
|
|
@ -199,9 +199,9 @@ impl PL011Registers {
|
|||
LCR_H => u32::from(self.line_control),
|
||||
CR => u32::from(self.control),
|
||||
FLS => self.ifl,
|
||||
IMSC => self.int_enabled,
|
||||
RIS => self.int_level,
|
||||
MIS => self.int_level & self.int_enabled,
|
||||
IMSC => u32::from(self.int_enabled),
|
||||
RIS => u32::from(self.int_level),
|
||||
MIS => u32::from(self.int_level & self.int_enabled),
|
||||
ICR => {
|
||||
// "The UARTICR Register is the interrupt clear register and is write-only"
|
||||
// Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
|
||||
|
|
@ -263,13 +263,13 @@ impl PL011Registers {
|
|||
self.set_read_trigger();
|
||||
}
|
||||
IMSC => {
|
||||
self.int_enabled = value;
|
||||
self.int_enabled = Interrupt::from(value);
|
||||
return true;
|
||||
}
|
||||
RIS => {}
|
||||
MIS => {}
|
||||
ICR => {
|
||||
self.int_level &= !value;
|
||||
self.int_level &= !Interrupt::from(value);
|
||||
return true;
|
||||
}
|
||||
DMACR => {
|
||||
|
|
@ -295,7 +295,7 @@ impl PL011Registers {
|
|||
self.flags.set_receive_fifo_empty(true);
|
||||
}
|
||||
if self.read_count + 1 == self.read_trigger {
|
||||
self.int_level &= !Interrupt::RX.0;
|
||||
self.int_level &= !Interrupt::RX;
|
||||
}
|
||||
self.receive_status_error_clear.set_from_data(c);
|
||||
*update = true;
|
||||
|
|
@ -305,7 +305,7 @@ impl PL011Registers {
|
|||
fn write_data_register(&mut self, value: u32) -> bool {
|
||||
// interrupts always checked
|
||||
let _ = self.loopback_tx(value.into());
|
||||
self.int_level |= Interrupt::TX.0;
|
||||
self.int_level |= Interrupt::TX;
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -361,19 +361,19 @@ impl PL011Registers {
|
|||
// Change interrupts based on updated FR
|
||||
let mut il = self.int_level;
|
||||
|
||||
il &= !Interrupt::MS.0;
|
||||
il &= !Interrupt::MS;
|
||||
|
||||
if self.flags.data_set_ready() {
|
||||
il |= Interrupt::DSR.0;
|
||||
il |= Interrupt::DSR;
|
||||
}
|
||||
if self.flags.data_carrier_detect() {
|
||||
il |= Interrupt::DCD.0;
|
||||
il |= Interrupt::DCD;
|
||||
}
|
||||
if self.flags.clear_to_send() {
|
||||
il |= Interrupt::CTS.0;
|
||||
il |= Interrupt::CTS;
|
||||
}
|
||||
if self.flags.ring_indicator() {
|
||||
il |= Interrupt::RI.0;
|
||||
il |= Interrupt::RI;
|
||||
}
|
||||
self.int_level = il;
|
||||
true
|
||||
|
|
@ -391,8 +391,8 @@ impl PL011Registers {
|
|||
self.line_control.reset();
|
||||
self.receive_status_error_clear.reset();
|
||||
self.dmacr = 0;
|
||||
self.int_enabled = 0;
|
||||
self.int_level = 0;
|
||||
self.int_enabled = 0.into();
|
||||
self.int_level = 0.into();
|
||||
self.ilpr = 0;
|
||||
self.ibrd = 0;
|
||||
self.fbrd = 0;
|
||||
|
|
@ -451,7 +451,7 @@ impl PL011Registers {
|
|||
}
|
||||
|
||||
if self.read_count == self.read_trigger {
|
||||
self.int_level |= Interrupt::RX.0;
|
||||
self.int_level |= Interrupt::RX;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
|
@ -632,7 +632,7 @@ impl PL011State {
|
|||
let regs = self.regs.borrow();
|
||||
let flags = regs.int_level & regs.int_enabled;
|
||||
for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
|
||||
irq.set(flags & i != 0);
|
||||
irq.set(flags.any_set(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -642,14 +642,13 @@ impl PL011State {
|
|||
}
|
||||
|
||||
/// Which bits in the interrupt status matter for each outbound IRQ line ?
|
||||
const IRQMASK: [u32; 6] = [
|
||||
/* combined IRQ */
|
||||
Interrupt::E.0 | Interrupt::MS.0 | Interrupt::RT.0 | Interrupt::TX.0 | Interrupt::RX.0,
|
||||
Interrupt::RX.0,
|
||||
Interrupt::TX.0,
|
||||
Interrupt::RT.0,
|
||||
Interrupt::MS.0,
|
||||
Interrupt::E.0,
|
||||
const IRQMASK: [Interrupt; 6] = [
|
||||
Interrupt::all(),
|
||||
Interrupt::RX,
|
||||
Interrupt::TX,
|
||||
Interrupt::RT,
|
||||
Interrupt::MS,
|
||||
Interrupt::E,
|
||||
];
|
||||
|
||||
/// # Safety
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
// https://developer.arm.com/documentation/ddi0183/latest/
|
||||
|
||||
use bilge::prelude::*;
|
||||
use qemu_api::impl_vmstate_bitsized;
|
||||
use bits::bits;
|
||||
use qemu_api::{impl_vmstate_bitsized, impl_vmstate_forward};
|
||||
|
||||
/// Offset of each register from the base memory address of the device.
|
||||
#[doc(alias = "offset")]
|
||||
|
|
@ -326,22 +327,24 @@ impl Default for Control {
|
|||
}
|
||||
}
|
||||
|
||||
/// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
|
||||
pub struct Interrupt(pub u32);
|
||||
bits! {
|
||||
/// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
|
||||
#[derive(Default)]
|
||||
pub struct Interrupt(u32) {
|
||||
OE = 1 << 10,
|
||||
BE = 1 << 9,
|
||||
PE = 1 << 8,
|
||||
FE = 1 << 7,
|
||||
RT = 1 << 6,
|
||||
TX = 1 << 5,
|
||||
RX = 1 << 4,
|
||||
DSR = 1 << 3,
|
||||
DCD = 1 << 2,
|
||||
CTS = 1 << 1,
|
||||
RI = 1 << 0,
|
||||
|
||||
impl Interrupt {
|
||||
pub const OE: Self = Self(1 << 10);
|
||||
pub const BE: Self = Self(1 << 9);
|
||||
pub const PE: Self = Self(1 << 8);
|
||||
pub const FE: Self = Self(1 << 7);
|
||||
pub const RT: Self = Self(1 << 6);
|
||||
pub const TX: Self = Self(1 << 5);
|
||||
pub const RX: Self = Self(1 << 4);
|
||||
pub const DSR: Self = Self(1 << 3);
|
||||
pub const DCD: Self = Self(1 << 2);
|
||||
pub const CTS: Self = Self(1 << 1);
|
||||
pub const RI: Self = Self(1 << 0);
|
||||
|
||||
pub const E: Self = Self(Self::OE.0 | Self::BE.0 | Self::PE.0 | Self::FE.0);
|
||||
pub const MS: Self = Self(Self::RI.0 | Self::DSR.0 | Self::DCD.0 | Self::CTS.0);
|
||||
E = bits!(Self as u32: OE | BE | PE | FE),
|
||||
MS = bits!(Self as u32: RI | DSR | DCD | CTS),
|
||||
}
|
||||
}
|
||||
impl_vmstate_forward!(Interrupt);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ quote_rs_native = dependency('quote-1-rs', native: true)
|
|||
syn_rs_native = dependency('syn-2-rs', native: true)
|
||||
proc_macro2_rs_native = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
qemuutil_rs = qemuutil.partial_dependency(link_args: true, links: true)
|
||||
|
||||
subdir('qemu-api-macros')
|
||||
subdir('bits')
|
||||
subdir('qemu-api')
|
||||
|
||||
subdir('hw')
|
||||
|
|
@ -22,21 +25,9 @@ subdir('hw')
|
|||
cargo = find_program('cargo', required: false)
|
||||
|
||||
if cargo.found()
|
||||
run_target('clippy',
|
||||
command: [config_host['MESON'], 'devenv',
|
||||
'--workdir', '@CURRENT_SOURCE_DIR@',
|
||||
cargo, 'clippy', '--tests'],
|
||||
depends: bindings_rs)
|
||||
|
||||
run_target('rustfmt',
|
||||
command: [config_host['MESON'], 'devenv',
|
||||
'--workdir', '@CURRENT_SOURCE_DIR@',
|
||||
cargo, 'fmt'],
|
||||
depends: bindings_rs)
|
||||
|
||||
run_target('rustdoc',
|
||||
command: [config_host['MESON'], 'devenv',
|
||||
'--workdir', '@CURRENT_SOURCE_DIR@',
|
||||
cargo, 'doc', '--no-deps', '--document-private-items'],
|
||||
depends: bindings_rs)
|
||||
endif
|
||||
|
|
|
|||
229
rust/qemu-api-macros/src/bits.rs
Normal file
229
rust/qemu-api-macros/src/bits.rs
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
// SPDX-License-Identifier: MIT or Apache-2.0 or GPL-2.0-or-later
|
||||
|
||||
// shadowing is useful together with "if let"
|
||||
#![allow(clippy::shadow_unrelated)]
|
||||
|
||||
use proc_macro2::{
|
||||
Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree, TokenTree as TT,
|
||||
};
|
||||
|
||||
use crate::utils::MacroError;
|
||||
|
||||
pub struct BitsConstInternal {
|
||||
typ: TokenTree,
|
||||
}
|
||||
|
||||
fn paren(ts: TokenStream) -> TokenTree {
|
||||
TT::Group(Group::new(Delimiter::Parenthesis, ts))
|
||||
}
|
||||
|
||||
fn ident(s: &'static str) -> TokenTree {
|
||||
TT::Ident(Ident::new(s, Span::call_site()))
|
||||
}
|
||||
|
||||
fn punct(ch: char) -> TokenTree {
|
||||
TT::Punct(Punct::new(ch, Spacing::Alone))
|
||||
}
|
||||
|
||||
/// Implements a recursive-descent parser that translates Boolean expressions on
|
||||
/// bitmasks to invocations of `const` functions defined by the `bits!` macro.
|
||||
impl BitsConstInternal {
|
||||
// primary ::= '(' or ')'
|
||||
// | ident
|
||||
// | '!' ident
|
||||
fn parse_primary(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
let next = match tok {
|
||||
TT::Group(ref g) => {
|
||||
if g.delimiter() != Delimiter::Parenthesis && g.delimiter() != Delimiter::None {
|
||||
return Err(MacroError::Message("expected parenthesis".into(), g.span()));
|
||||
}
|
||||
let mut stream = g.stream().into_iter();
|
||||
let Some(first_tok) = stream.next() else {
|
||||
return Err(MacroError::Message(
|
||||
"expected operand, found ')'".into(),
|
||||
g.span(),
|
||||
));
|
||||
};
|
||||
let mut output = TokenStream::new();
|
||||
// start from the lowest precedence
|
||||
let next = self.parse_or(first_tok, &mut stream, &mut output)?;
|
||||
if let Some(tok) = next {
|
||||
return Err(MacroError::Message(
|
||||
format!("unexpected token {tok}"),
|
||||
tok.span(),
|
||||
));
|
||||
}
|
||||
out.extend(Some(paren(output)));
|
||||
it.next()
|
||||
}
|
||||
TT::Ident(_) => {
|
||||
let mut output = TokenStream::new();
|
||||
output.extend([
|
||||
self.typ.clone(),
|
||||
TT::Punct(Punct::new(':', Spacing::Joint)),
|
||||
TT::Punct(Punct::new(':', Spacing::Joint)),
|
||||
tok,
|
||||
]);
|
||||
out.extend(Some(paren(output)));
|
||||
it.next()
|
||||
}
|
||||
TT::Punct(ref p) => {
|
||||
if p.as_char() != '!' {
|
||||
return Err(MacroError::Message("expected operand".into(), p.span()));
|
||||
}
|
||||
let Some(rhs_tok) = it.next() else {
|
||||
return Err(MacroError::Message(
|
||||
"expected operand at end of input".into(),
|
||||
p.span(),
|
||||
));
|
||||
};
|
||||
let next = self.parse_primary(rhs_tok, it, out)?;
|
||||
out.extend([punct('.'), ident("invert"), paren(TokenStream::new())]);
|
||||
next
|
||||
}
|
||||
_ => {
|
||||
return Err(MacroError::Message("unexpected literal".into(), tok.span()));
|
||||
}
|
||||
};
|
||||
Ok(next)
|
||||
}
|
||||
|
||||
fn parse_binop<
|
||||
F: Fn(
|
||||
&Self,
|
||||
TokenTree,
|
||||
&mut dyn Iterator<Item = TokenTree>,
|
||||
&mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError>,
|
||||
>(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
ch: char,
|
||||
f: F,
|
||||
method: &'static str,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
let mut next = f(self, tok, it, out)?;
|
||||
while next.is_some() {
|
||||
let op = next.as_ref().unwrap();
|
||||
let TT::Punct(ref p) = op else { break };
|
||||
if p.as_char() != ch {
|
||||
break;
|
||||
}
|
||||
|
||||
let Some(rhs_tok) = it.next() else {
|
||||
return Err(MacroError::Message(
|
||||
"expected operand at end of input".into(),
|
||||
p.span(),
|
||||
));
|
||||
};
|
||||
let mut rhs = TokenStream::new();
|
||||
next = f(self, rhs_tok, it, &mut rhs)?;
|
||||
out.extend([punct('.'), ident(method), paren(rhs)]);
|
||||
}
|
||||
Ok(next)
|
||||
}
|
||||
|
||||
// sub ::= primary ('-' primary)*
|
||||
pub fn parse_sub(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
self.parse_binop(tok, it, out, '-', Self::parse_primary, "difference")
|
||||
}
|
||||
|
||||
// and ::= sub ('&' sub)*
|
||||
fn parse_and(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
self.parse_binop(tok, it, out, '&', Self::parse_sub, "intersection")
|
||||
}
|
||||
|
||||
// xor ::= and ('&' and)*
|
||||
fn parse_xor(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
self.parse_binop(tok, it, out, '^', Self::parse_and, "symmetric_difference")
|
||||
}
|
||||
|
||||
// or ::= xor ('|' xor)*
|
||||
pub fn parse_or(
|
||||
&self,
|
||||
tok: TokenTree,
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
out: &mut TokenStream,
|
||||
) -> Result<Option<TokenTree>, MacroError> {
|
||||
self.parse_binop(tok, it, out, '|', Self::parse_xor, "union")
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
it: &mut dyn Iterator<Item = TokenTree>,
|
||||
) -> Result<proc_macro2::TokenStream, MacroError> {
|
||||
let mut pos = Span::call_site();
|
||||
let mut typ = proc_macro2::TokenStream::new();
|
||||
|
||||
// Gobble everything up to an `@` sign, which is followed by a
|
||||
// parenthesized expression; that is, all token trees except the
|
||||
// last two form the type.
|
||||
let next = loop {
|
||||
let tok = it.next();
|
||||
if let Some(ref t) = tok {
|
||||
pos = t.span();
|
||||
}
|
||||
match tok {
|
||||
None => break None,
|
||||
Some(TT::Punct(ref p)) if p.as_char() == '@' => {
|
||||
let tok = it.next();
|
||||
if let Some(ref t) = tok {
|
||||
pos = t.span();
|
||||
}
|
||||
break tok;
|
||||
}
|
||||
Some(x) => typ.extend(Some(x)),
|
||||
}
|
||||
};
|
||||
|
||||
let Some(tok) = next else {
|
||||
return Err(MacroError::Message(
|
||||
"expected expression, do not call this macro directly".into(),
|
||||
pos,
|
||||
));
|
||||
};
|
||||
let TT::Group(ref _group) = tok else {
|
||||
return Err(MacroError::Message(
|
||||
"expected parenthesis, do not call this macro directly".into(),
|
||||
tok.span(),
|
||||
));
|
||||
};
|
||||
let mut out = TokenStream::new();
|
||||
let state = Self {
|
||||
typ: TT::Group(Group::new(Delimiter::None, typ)),
|
||||
};
|
||||
|
||||
let next = state.parse_primary(tok, it, &mut out)?;
|
||||
|
||||
// A parenthesized expression is a single production of the grammar,
|
||||
// so the input must have reached the last token.
|
||||
if let Some(tok) = next {
|
||||
return Err(MacroError::Message(
|
||||
format!("unexpected token {tok}"),
|
||||
tok.span(),
|
||||
));
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,9 @@ use syn::{
|
|||
mod utils;
|
||||
use utils::MacroError;
|
||||
|
||||
mod bits;
|
||||
use bits::BitsConstInternal;
|
||||
|
||||
fn get_fields<'a>(
|
||||
input: &'a DeriveInput,
|
||||
msg: &str,
|
||||
|
|
@ -190,23 +193,51 @@ fn get_variants(input: &DeriveInput) -> Result<&Punctuated<Variant, Comma>, Macr
|
|||
}
|
||||
|
||||
#[rustfmt::skip::macros(quote)]
|
||||
fn derive_tryinto_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
|
||||
let repr = get_repr_uN(&input, "#[derive(TryInto)]")?;
|
||||
|
||||
let name = &input.ident;
|
||||
let variants = get_variants(&input)?;
|
||||
fn derive_tryinto_body(
|
||||
name: &Ident,
|
||||
variants: &Punctuated<Variant, Comma>,
|
||||
repr: &Path,
|
||||
) -> Result<proc_macro2::TokenStream, MacroError> {
|
||||
let discriminants: Vec<&Ident> = variants.iter().map(|f| &f.ident).collect();
|
||||
|
||||
Ok(quote! {
|
||||
#(const #discriminants: #repr = #name::#discriminants as #repr;)*;
|
||||
match value {
|
||||
#(#discriminants => Ok(#name::#discriminants),)*
|
||||
_ => Err(value),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[rustfmt::skip::macros(quote)]
|
||||
fn derive_tryinto_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
|
||||
let repr = get_repr_uN(&input, "#[derive(TryInto)]")?;
|
||||
let name = &input.ident;
|
||||
let body = derive_tryinto_body(name, get_variants(&input)?, &repr)?;
|
||||
let errmsg = format!("invalid value for {name}");
|
||||
|
||||
Ok(quote! {
|
||||
impl #name {
|
||||
#[allow(dead_code)]
|
||||
pub const fn into_bits(self) -> #repr {
|
||||
self as #repr
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const fn from_bits(value: #repr) -> Self {
|
||||
match ({
|
||||
#body
|
||||
}) {
|
||||
Ok(x) => x,
|
||||
Err(_) => panic!(#errmsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl core::convert::TryFrom<#repr> for #name {
|
||||
type Error = #repr;
|
||||
|
||||
fn try_from(value: #repr) -> Result<Self, Self::Error> {
|
||||
#(const #discriminants: #repr = #name::#discriminants as #repr;)*;
|
||||
match value {
|
||||
#(#discriminants => Ok(Self::#discriminants),)*
|
||||
_ => Err(value),
|
||||
}
|
||||
#body
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -219,3 +250,12 @@ pub fn derive_tryinto(input: TokenStream) -> TokenStream {
|
|||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn bits_const_internal(ts: TokenStream) -> TokenStream {
|
||||
let ts = proc_macro2::TokenStream::from(ts);
|
||||
let mut it = ts.into_iter();
|
||||
|
||||
let expanded = BitsConstInternal::parse(&mut it).unwrap_or_else(Into::into);
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,32 +35,24 @@ _qemu_api_rs = static_library(
|
|||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: _qemu_api_cfg,
|
||||
dependencies: [libc_rs, qemu_api_macros],
|
||||
dependencies: [libc_rs, qemu_api_macros, qemuutil_rs,
|
||||
qom, hwcore, chardev, migration],
|
||||
)
|
||||
|
||||
rust.test('rust-qemu-api-tests', _qemu_api_rs,
|
||||
suite: ['unit', 'rust'])
|
||||
|
||||
qemu_api = declare_dependency(link_with: _qemu_api_rs)
|
||||
qemu_api = declare_dependency(link_with: [_qemu_api_rs],
|
||||
dependencies: [qemu_api_macros, qom, hwcore, chardev, migration])
|
||||
|
||||
# Rust executables do not support objects, so add an intermediate step.
|
||||
rust_qemu_api_objs = static_library(
|
||||
'rust_qemu_api_objs',
|
||||
objects: [libqom.extract_all_objects(recursive: false),
|
||||
libhwcore.extract_all_objects(recursive: false),
|
||||
libchardev.extract_all_objects(recursive: false),
|
||||
libcrypto.extract_all_objects(recursive: false),
|
||||
libauthz.extract_all_objects(recursive: false),
|
||||
libio.extract_all_objects(recursive: false),
|
||||
libmigration.extract_all_objects(recursive: false)])
|
||||
rust_qemu_api_deps = declare_dependency(
|
||||
dependencies: [
|
||||
qom_ss.dependencies(),
|
||||
chardev_ss.dependencies(),
|
||||
crypto_ss.dependencies(),
|
||||
authz_ss.dependencies(),
|
||||
io_ss.dependencies()],
|
||||
link_whole: [rust_qemu_api_objs, libqemuutil])
|
||||
# Doctests are essentially integration tests, so they need the same dependencies.
|
||||
# Note that running them requires the object files for C code, so place them
|
||||
# in a separate suite that is run by the "build" CI jobs rather than "check".
|
||||
rust.doctest('rust-qemu-api-doctests',
|
||||
_qemu_api_rs,
|
||||
protocol: 'rust',
|
||||
dependencies: qemu_api,
|
||||
suite: ['doc', 'rust'])
|
||||
|
||||
test('rust-qemu-api-integration',
|
||||
executable(
|
||||
|
|
@ -69,7 +61,7 @@ test('rust-qemu-api-integration',
|
|||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_args: ['--test'],
|
||||
install: false,
|
||||
dependencies: [qemu_api, qemu_api_macros, rust_qemu_api_deps]),
|
||||
dependencies: [qemu_api]),
|
||||
args: [
|
||||
'--test', '--test-threads', '1',
|
||||
'--format', 'pretty',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
clippy::restriction,
|
||||
clippy::style,
|
||||
clippy::missing_const_for_fn,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::useless_transmute,
|
||||
clippy::missing_safety_doc
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -225,27 +225,23 @@ use crate::bindings;
|
|||
|
||||
/// An internal function that is used by doctests.
|
||||
pub fn bql_start_test() {
|
||||
if cfg!(MESON) {
|
||||
// SAFETY: integration tests are run with --test-threads=1, while
|
||||
// unit tests and doctests are not multithreaded and do not have
|
||||
// any BQL-protected data. Just set bql_locked to true.
|
||||
unsafe {
|
||||
bindings::rust_bql_mock_lock();
|
||||
}
|
||||
// SAFETY: integration tests are run with --test-threads=1, while
|
||||
// unit tests and doctests are not multithreaded and do not have
|
||||
// any BQL-protected data. Just set bql_locked to true.
|
||||
unsafe {
|
||||
bindings::rust_bql_mock_lock();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bql_locked() -> bool {
|
||||
// SAFETY: the function does nothing but return a thread-local bool
|
||||
!cfg!(MESON) || unsafe { bindings::bql_locked() }
|
||||
unsafe { bindings::bql_locked() }
|
||||
}
|
||||
|
||||
fn bql_block_unlock(increase: bool) {
|
||||
if cfg!(MESON) {
|
||||
// SAFETY: this only adjusts a counter
|
||||
unsafe {
|
||||
bindings::bql_block_unlock(increase);
|
||||
}
|
||||
// SAFETY: this only adjusts a counter
|
||||
unsafe {
|
||||
bindings::bql_block_unlock(increase);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,10 +104,7 @@ def generate_lint_flags(cargo_toml: CargoTOML, strict_lints: bool) -> Iterable[s
|
|||
else:
|
||||
raise Exception(f"invalid level {level} for {prefix}{lint}")
|
||||
|
||||
# This may change if QEMU ever invokes clippy-driver or rustdoc by
|
||||
# hand. For now, check the syntax but do not add non-rustc lints to
|
||||
# the command line.
|
||||
if k == "rust" and not (strict_lints and lint in STRICT_LINTS):
|
||||
if not (strict_lints and lint in STRICT_LINTS):
|
||||
lint_list.append(LintFlag(flags=[flag, prefix + lint], priority=priority))
|
||||
|
||||
if strict_lints:
|
||||
|
|
|
|||
|
|
@ -900,6 +900,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
|||
|
||||
#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \
|
||||
CPUID_7_1_EAX_FSRC | CPUID_7_1_EAX_CMPCCXADD)
|
||||
#define TCG_7_1_ECX_FEATURES 0
|
||||
#define TCG_7_1_EDX_FEATURES 0
|
||||
#define TCG_7_2_EDX_FEATURES 0
|
||||
#define TCG_APM_FEATURES 0
|
||||
|
|
@ -1150,6 +1151,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
|||
},
|
||||
.tcg_features = TCG_7_1_EAX_FEATURES,
|
||||
},
|
||||
[FEAT_7_1_ECX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, "msr-imm", 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 = 7,
|
||||
.needs_ecx = true, .ecx = 1,
|
||||
.reg = R_ECX,
|
||||
},
|
||||
.tcg_features = TCG_7_1_ECX_FEATURES,
|
||||
},
|
||||
[FEAT_7_1_EDX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
|
|
@ -1803,10 +1823,6 @@ static FeatureDep feature_dependencies[] = {
|
|||
.from = { FEAT_7_1_EAX, CPUID_7_1_EAX_LKGS },
|
||||
.to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED },
|
||||
},
|
||||
{
|
||||
.from = { FEAT_7_1_EAX, CPUID_7_1_EAX_WRMSRNS },
|
||||
.to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED },
|
||||
},
|
||||
{
|
||||
.from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
|
||||
.to = { FEAT_7_0_ECX, CPUID_7_0_ECX_SGX_LC },
|
||||
|
|
@ -7446,9 +7462,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||
*edx = env->features[FEAT_7_0_EDX]; /* Feature flags */
|
||||
} else if (count == 1) {
|
||||
*eax = env->features[FEAT_7_1_EAX];
|
||||
*ecx = env->features[FEAT_7_1_ECX];
|
||||
*edx = env->features[FEAT_7_1_EDX];
|
||||
*ebx = 0;
|
||||
*ecx = 0;
|
||||
} else if (count == 2) {
|
||||
*edx = env->features[FEAT_7_2_EDX];
|
||||
*eax = 0;
|
||||
|
|
@ -8353,6 +8369,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
|||
x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_7_1_ECX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX);
|
||||
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX);
|
||||
|
|
|
|||
|
|
@ -668,6 +668,7 @@ typedef enum FeatureWord {
|
|||
FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */
|
||||
FEAT_XSAVE_XSS_LO, /* CPUID[EAX=0xd,ECX=1].ECX */
|
||||
FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */
|
||||
FEAT_7_1_ECX, /* CPUID[EAX=7,ECX=1].ECX */
|
||||
FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */
|
||||
FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */
|
||||
FEAT_24_0_EBX, /* CPUID[EAX=0x24,ECX=0].EBX */
|
||||
|
|
@ -1000,6 +1001,9 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
/* Linear Address Masking */
|
||||
#define CPUID_7_1_EAX_LAM (1U << 26)
|
||||
|
||||
/* The immediate form of MSR access instructions */
|
||||
#define CPUID_7_1_ECX_MSR_IMM (1U << 5)
|
||||
|
||||
/* Support for VPDPB[SU,UU,SS]D[,S] */
|
||||
#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4)
|
||||
/* AVX NE CONVERT Instructions */
|
||||
|
|
@ -1023,6 +1027,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
|
|||
#define CPUID_7_2_EDX_DDPD_U (1U << 3)
|
||||
/* Indicate bit 10 of the IA32_SPEC_CTRL MSR is supported */
|
||||
#define CPUID_7_2_EDX_BHI_CTRL (1U << 4)
|
||||
|
||||
/* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */
|
||||
#define CPUID_7_2_EDX_MCDT_NO (1U << 5)
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ static void tdx_post_init_vcpus(void)
|
|||
|
||||
hob = tdx_get_hob_entry(tdx_guest);
|
||||
CPU_FOREACH(cpu) {
|
||||
tdx_vcpu_ioctl(cpu, KVM_TDX_INIT_VCPU, 0, (void *)hob->address,
|
||||
tdx_vcpu_ioctl(cpu, KVM_TDX_INIT_VCPU, 0, (void *)(uintptr_t)hob->address,
|
||||
&error_fatal);
|
||||
}
|
||||
}
|
||||
|
|
@ -339,7 +339,7 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused)
|
|||
uint32_t flags;
|
||||
|
||||
region = (struct kvm_tdx_init_mem_region) {
|
||||
.source_addr = (uint64_t)entry->mem_ptr,
|
||||
.source_addr = (uintptr_t)entry->mem_ptr,
|
||||
.gpa = entry->address,
|
||||
.nr_pages = entry->size >> 12,
|
||||
};
|
||||
|
|
@ -893,16 +893,16 @@ static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs)
|
|||
static int tdx_validate_attributes(TdxGuest *tdx, Error **errp)
|
||||
{
|
||||
if ((tdx->attributes & ~tdx_caps->supported_attrs)) {
|
||||
error_setg(errp, "Invalid attributes 0x%lx for TDX VM "
|
||||
"(KVM supported: 0x%llx)", tdx->attributes,
|
||||
tdx_caps->supported_attrs);
|
||||
error_setg(errp, "Invalid attributes 0x%"PRIx64" for TDX VM "
|
||||
"(KVM supported: 0x%"PRIx64")", tdx->attributes,
|
||||
(uint64_t)tdx_caps->supported_attrs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tdx->attributes & ~TDX_SUPPORTED_TD_ATTRS) {
|
||||
error_setg(errp, "Some QEMU unsupported TD attribute bits being "
|
||||
"requested: 0x%lx (QEMU supported: 0x%llx)",
|
||||
tdx->attributes, TDX_SUPPORTED_TD_ATTRS);
|
||||
"requested: 0x%"PRIx64" (QEMU supported: 0x%"PRIx64")",
|
||||
tdx->attributes, (uint64_t)TDX_SUPPORTED_TD_ATTRS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -931,8 +931,8 @@ static int setup_td_xfam(X86CPU *x86cpu, Error **errp)
|
|||
env->features[FEAT_XSAVE_XSS_HI];
|
||||
|
||||
if (xfam & ~tdx_caps->supported_xfam) {
|
||||
error_setg(errp, "Invalid XFAM 0x%lx for TDX VM (supported: 0x%llx))",
|
||||
xfam, tdx_caps->supported_xfam);
|
||||
error_setg(errp, "Invalid XFAM 0x%"PRIx64" for TDX VM (supported: 0x%"PRIx64"))",
|
||||
xfam, (uint64_t)tdx_caps->supported_xfam);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -999,14 +999,14 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp)
|
|||
|
||||
if (env->tsc_khz && (env->tsc_khz < TDX_MIN_TSC_FREQUENCY_KHZ ||
|
||||
env->tsc_khz > TDX_MAX_TSC_FREQUENCY_KHZ)) {
|
||||
error_setg(errp, "Invalid TSC %ld KHz, must specify cpu_frequency "
|
||||
error_setg(errp, "Invalid TSC %"PRId64" KHz, must specify cpu_frequency "
|
||||
"between [%d, %d] kHz", env->tsc_khz,
|
||||
TDX_MIN_TSC_FREQUENCY_KHZ, TDX_MAX_TSC_FREQUENCY_KHZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (env->tsc_khz % (25 * 1000)) {
|
||||
error_setg(errp, "Invalid TSC %ld KHz, it must be multiple of 25MHz",
|
||||
error_setg(errp, "Invalid TSC %"PRId64" KHz, it must be multiple of 25MHz",
|
||||
env->tsc_khz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1014,7 +1014,7 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp)
|
|||
/* it's safe even env->tsc_khz is 0. KVM uses host's tsc_khz in this case */
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_SET_TSC_KHZ, env->tsc_khz);
|
||||
if (r < 0) {
|
||||
error_setg_errno(errp, -r, "Unable to set TSC frequency to %ld kHz",
|
||||
error_setg_errno(errp, -r, "Unable to set TSC frequency to %"PRId64" kHz",
|
||||
env->tsc_khz);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1139,7 +1139,7 @@ int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run)
|
|||
uint64_t gpa = -1ull;
|
||||
|
||||
if (error_code & 0xffff) {
|
||||
error_report("TDX: REPORT_FATAL_ERROR: invalid error code: 0x%lx",
|
||||
error_report("TDX: REPORT_FATAL_ERROR: invalid error code: 0x%"PRIx64,
|
||||
error_code);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ ENV PYTHON "/usr/bin/python3"
|
|||
RUN dnf install -y wget
|
||||
ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
|
||||
ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc
|
||||
ENV RUSTDOC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustdoc
|
||||
ENV CARGO=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo
|
||||
RUN set -eux && \
|
||||
rustArch='x86_64-unknown-linux-gnu' && \
|
||||
|
|
@ -170,6 +171,7 @@ RUN set -eux && \
|
|||
/usr/local/cargo/bin/rustup run nightly cargo --version && \
|
||||
/usr/local/cargo/bin/rustup run nightly rustc --version && \
|
||||
test "$CARGO" = "$(/usr/local/cargo/bin/rustup +nightly which cargo)" && \
|
||||
test "$RUSTDOC" = "$(/usr/local/cargo/bin/rustup +nightly which rustdoc)" && \
|
||||
test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"
|
||||
ENV PATH=$CARGO_HOME/bin:$PATH
|
||||
RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ ENV MAKE "/usr/bin/make"
|
|||
ENV NINJA "/usr/bin/ninja"
|
||||
ENV PYTHON "/usr/bin/python3"
|
||||
ENV RUSTC=/usr/bin/rustc-1.77
|
||||
ENV RUSTDOC=/usr/bin/rustdoc-1.77
|
||||
ENV CARGO_HOME=/usr/local/cargo
|
||||
ENV PATH=$CARGO_HOME/bin:$PATH
|
||||
RUN DEBIAN_FRONTEND=noninteractive eatmydata \
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ mappings:
|
|||
|
||||
meson:
|
||||
OpenSUSELeap15:
|
||||
# Use Meson from PyPI wherever Rust is enabled
|
||||
Debian:
|
||||
Fedora:
|
||||
Ubuntu:
|
||||
|
||||
python3:
|
||||
OpenSUSELeap15: python311-base
|
||||
|
|
@ -72,7 +76,7 @@ mappings:
|
|||
pypi_mappings:
|
||||
# Request more recent version
|
||||
meson:
|
||||
default: meson==1.5.0
|
||||
default: meson==1.8.1
|
||||
|
||||
# Drop packages that need devel headers
|
||||
python3-numpy:
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ fedora_rustup_nightly_extras = [
|
|||
"RUN dnf install -y wget\n",
|
||||
"ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo\n",
|
||||
"ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc\n",
|
||||
"ENV RUSTDOC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustdoc\n",
|
||||
"ENV CARGO=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo\n",
|
||||
"RUN set -eux && \\\n",
|
||||
" rustArch='x86_64-unknown-linux-gnu' && \\\n",
|
||||
|
|
@ -135,6 +136,7 @@ fedora_rustup_nightly_extras = [
|
|||
" /usr/local/cargo/bin/rustup run nightly cargo --version && \\\n",
|
||||
" /usr/local/cargo/bin/rustup run nightly rustc --version && \\\n",
|
||||
' test "$CARGO" = "$(/usr/local/cargo/bin/rustup +nightly which cargo)" && \\\n',
|
||||
' test "$RUSTDOC" = "$(/usr/local/cargo/bin/rustup +nightly which rustdoc)" && \\\n',
|
||||
' test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"\n',
|
||||
'ENV PATH=$CARGO_HOME/bin:$PATH\n',
|
||||
'RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli\n',
|
||||
|
|
@ -143,6 +145,7 @@ fedora_rustup_nightly_extras = [
|
|||
|
||||
ubuntu2204_rust_extras = [
|
||||
"ENV RUSTC=/usr/bin/rustc-1.77\n",
|
||||
"ENV RUSTDOC=/usr/bin/rustdoc-1.77\n",
|
||||
"ENV CARGO_HOME=/usr/local/cargo\n",
|
||||
'ENV PATH=$CARGO_HOME/bin:$PATH\n',
|
||||
"RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue