From fcbe1080a4cb16767cdda788504f9793cbbe0532 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 19 Sep 2025 09:35:44 +0200 Subject: [PATCH 01/29] docs: use the pyvenv version of Meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version in the system might be too old for QEMU; this will be especially true if Rust is going to be enabled by default. Adjust the docs to suggest using pyvenv/bin/meson, which is in fact what the "make" wrappers will be running internally. Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- docs/devel/build-system.rst | 2 +- docs/devel/rust.rst | 2 +- docs/system/devices/igb.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 2c884197a2..6204aa6a72 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -450,7 +450,7 @@ are run with ``make bench``. Meson test suites such as ``unit`` can be ran with ``make check-unit``, and ``make check-tcg`` builds and runs "non-Meson" tests for all targets. -If desired, it is also possible to use ``ninja`` and ``meson test``, +If desired, it is also possible to use ``ninja`` and ``pyvenv/bin/meson test``, respectively to build emulators and run tests defined in meson.build. The main difference is that ``make`` needs the ``-jN`` flag in order to enable parallel builds or tests. diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 13a20e86a1..2f0ab2e282 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -66,7 +66,7 @@ __ https://mesonbuild.com/Commands.html#devenv As shown above, you can use the ``--tests`` option as usual to operate on test code. Note however that you cannot *build* or run tests via ``cargo``, because they need support C code from QEMU that Cargo does not know about. Tests can -be run via ``meson test`` or ``make``:: +be run via Meson (``pyvenv/bin/meson test``) or ``make``:: make check-rust diff --git a/docs/system/devices/igb.rst b/docs/system/devices/igb.rst index 71f31cb116..50f625fd77 100644 --- a/docs/system/devices/igb.rst +++ b/docs/system/devices/igb.rst @@ -54,7 +54,7 @@ directory: .. code-block:: shell - meson test qtest-x86_64/qos-test + pyvenv/bin/meson test qtest-x86_64/qos-test ethtool can test register accesses, interrupts, etc. It is automated as an functional test and can be run from the build directory with the following From b9e8bb6637d5f2926121d68e4f227ba0e0a44186 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 19 Sep 2025 10:23:58 +0200 Subject: [PATCH 02/29] rust: build: add back common and util tests These were dropped by mistake when extracting the crates. Reviewed-by: Manos Pitsidianakis Signed-off-by: Paolo Bonzini --- rust/common/meson.build | 3 +++ rust/util/meson.build | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/rust/common/meson.build b/rust/common/meson.build index b805e0faf5..07d073182e 100644 --- a/rust/common/meson.build +++ b/rust/common/meson.build @@ -24,6 +24,9 @@ _common_rs = static_library( common_rs = declare_dependency(link_with: [_common_rs]) +rust.test('rust-common-tests', _common_rs, + suite: ['unit', 'rust']) + # 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". diff --git a/rust/util/meson.build b/rust/util/meson.build index 87a893673d..9633050445 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -44,6 +44,10 @@ _util_rs = static_library( util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom]) +rust.test('rust-util-tests', _util_rs, + dependencies: [qemuutil, qom], + suite: ['unit', 'rust']) + # 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". From 75dbe618ac3895b2889a590de3bc589bf32dc999 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Sep 2025 12:40:29 +0200 Subject: [PATCH 03/29] rust: vmstate: use "cast()" instead of "as" Reported by clippy, fix it. Reviewed-by: Manos Pitsidianakis Signed-off-by: Paolo Bonzini --- rust/migration/src/vmstate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index c05c4a1fd6..e04b19b3c9 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -144,7 +144,7 @@ macro_rules! vmstate_of { $crate::bindings::VMStateField { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() - .as_ptr() as *const ::std::os::raw::c_char, + .as_ptr().cast::<::std::os::raw::c_char>(), offset: ::std::mem::offset_of!($struct_name, $field_name), $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? From f87a2e5c596620a606aaa7df4257c45c4988e160 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 19 Sep 2025 12:16:25 +0200 Subject: [PATCH 04/29] rust: build: remove "protocol: rust: from doctests It is added already by rust.doctest. Reviewed-by: Manos Pitsidianakis Signed-off-by: Paolo Bonzini --- rust/bql/meson.build | 1 - rust/common/meson.build | 1 - rust/migration/meson.build | 1 - rust/qom/meson.build | 1 - rust/util/meson.build | 1 - 5 files changed, 5 deletions(-) diff --git a/rust/bql/meson.build b/rust/bql/meson.build index f369209dfd..7214d94408 100644 --- a/rust/bql/meson.build +++ b/rust/bql/meson.build @@ -47,6 +47,5 @@ bql_rs = declare_dependency(link_with: [_bql_rs], # in a separate suite that is run by the "build" CI jobs rather than "check". rust.doctest('rust-bql-rs-doctests', _bql_rs, - protocol: 'rust', dependencies: bql_rs, suite: ['doc', 'rust']) diff --git a/rust/common/meson.build b/rust/common/meson.build index 07d073182e..aff601d1df 100644 --- a/rust/common/meson.build +++ b/rust/common/meson.build @@ -32,6 +32,5 @@ rust.test('rust-common-tests', _common_rs, # in a separate suite that is run by the "build" CI jobs rather than "check". rust.doctest('rust-common-doctests', _common_rs, - protocol: 'rust', dependencies: common_rs, suite: ['doc', 'rust']) diff --git a/rust/migration/meson.build b/rust/migration/meson.build index 5e820d43f5..2a49bd1633 100644 --- a/rust/migration/meson.build +++ b/rust/migration/meson.build @@ -48,6 +48,5 @@ migration_rs = declare_dependency(link_with: [_migration_rs], # in a separate suite that is run by the "build" CI jobs rather than "check". rust.doctest('rust-migration-rs-doctests', _migration_rs, - protocol: 'rust', dependencies: migration_rs, suite: ['doc', 'rust']) diff --git a/rust/qom/meson.build b/rust/qom/meson.build index 40c51b71b2..21e12148da 100644 --- a/rust/qom/meson.build +++ b/rust/qom/meson.build @@ -38,6 +38,5 @@ qom_rs = declare_dependency(link_with: [_qom_rs], dependencies: [qemu_macros, qo # in a separate suite that is run by the "build" CI jobs rather than "check". rust.doctest('rust-qom-rs-doctests', _qom_rs, - protocol: 'rust', dependencies: qom_rs, suite: ['doc', 'rust']) diff --git a/rust/util/meson.build b/rust/util/meson.build index 9633050445..7ca69939ce 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -53,7 +53,6 @@ rust.test('rust-util-tests', _util_rs, # in a separate suite that is run by the "build" CI jobs rather than "check". rust.doctest('rust-util-rs-doctests', _util_rs, - protocol: 'rust', dependencies: util_rs, suite: ['doc', 'rust'] ) From 193f2ab6e076f0f3d07081802bee2d36eb86086f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 17 Jul 2025 08:02:15 +0200 Subject: [PATCH 05/29] subprojects: add attrs crate The attrs crate is a simple combinator-based for Rust attributes. It will be used instead of a handwritten parser. Signed-off-by: Paolo Bonzini --- rust/meson.build | 2 ++ rust/qemu-macros/Cargo.toml | 1 + rust/qemu-macros/meson.build | 1 + scripts/archive-source.sh | 2 +- scripts/make-release | 2 +- subprojects/.gitignore | 1 + subprojects/attrs-0.2-rs.wrap | 7 ++++ .../packagefiles/attrs-0.2-rs/meson.build | 33 +++++++++++++++++++ 8 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 subprojects/attrs-0.2-rs.wrap create mode 100644 subprojects/packagefiles/attrs-0.2-rs/meson.build diff --git a/rust/meson.build b/rust/meson.build index c7bd6aba45..b3ac3a7197 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -13,10 +13,12 @@ libc_rs = dependency('libc-0.2-rs') subproject('proc-macro2-1-rs', required: true) subproject('quote-1-rs', required: true) subproject('syn-2-rs', required: true) +subproject('attrs-0.2-rs', required: true) 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) +attrs_rs_native = dependency('attrs-0.2-rs', native: true) genrs = [] diff --git a/rust/qemu-macros/Cargo.toml b/rust/qemu-macros/Cargo.toml index 3b6f1d337f..c25b6c0b0d 100644 --- a/rust/qemu-macros/Cargo.toml +++ b/rust/qemu-macros/Cargo.toml @@ -16,6 +16,7 @@ rust-version.workspace = true proc-macro = true [dependencies] +attrs = "0.2.9" proc-macro2 = "1" quote = "1" syn = { version = "2", features = ["extra-traits"] } diff --git a/rust/qemu-macros/meson.build b/rust/qemu-macros/meson.build index d0b2992e20..0f27e0df92 100644 --- a/rust/qemu-macros/meson.build +++ b/rust/qemu-macros/meson.build @@ -8,6 +8,7 @@ _qemu_macros_rs = rust.proc_macro( '--cfg', 'feature="proc-macro"', ], dependencies: [ + attrs_rs_native, proc_macro2_rs_native, quote_rs_native, syn_rs_native, diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index 035828c532..476a996a70 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -27,7 +27,7 @@ sub_file="${sub_tdir}/submodule.tar" # in their checkout, because the build environment is completely # different to the host OS. subprojects="keycodemapdb libvfio-user berkeley-softfloat-3 - berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs bilge-0.2-rs + berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs libc-0.2-rs proc-macro2-1-rs proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs diff --git a/scripts/make-release b/scripts/make-release index 87f563ef5f..bc1b43caa2 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -40,7 +40,7 @@ fi # Only include wraps that are invoked with subproject() SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 - berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs bilge-0.2-rs + berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs libc-0.2-rs proc-macro2-1-rs proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs diff --git a/subprojects/.gitignore b/subprojects/.gitignore index f4281934ce..983c4c1549 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -8,6 +8,7 @@ /slirp /anyhow-1.0.98 /arbitrary-int-1.2.7 +/attrs-0.2.9 /bilge-0.2.0 /bilge-impl-0.2.0 /either-1.12.0 diff --git a/subprojects/attrs-0.2-rs.wrap b/subprojects/attrs-0.2-rs.wrap new file mode 100644 index 0000000000..cd43c91d63 --- /dev/null +++ b/subprojects/attrs-0.2-rs.wrap @@ -0,0 +1,7 @@ +[wrap-file] +directory = attrs-0.2.9 +source_url = https://crates.io/api/v1/crates/attrs/0.2.9/download +source_filename = attrs-0.2.9.tar.gz +source_hash = 2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f +#method = cargo +patch_directory = attrs-0.2-rs diff --git a/subprojects/packagefiles/attrs-0.2-rs/meson.build b/subprojects/packagefiles/attrs-0.2-rs/meson.build new file mode 100644 index 0000000000..ee575476cb --- /dev/null +++ b/subprojects/packagefiles/attrs-0.2-rs/meson.build @@ -0,0 +1,33 @@ +project('attrs-0.2-rs', 'rust', + meson_version: '>=1.5.0', + version: '0.2.9', + license: 'MIT OR Apache-2.0', + default_options: []) + +subproject('proc-macro2-1-rs', required: true) +subproject('syn-2-rs', required: true) + +proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) +syn_dep = dependency('syn-2-rs', native: true) + +_attrs_rs = static_library( + 'attrs', + files('src/lib.rs'), + gnu_symbol_visibility: 'hidden', + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + rust_args: [ + '--cap-lints', 'allow', + ], + dependencies: [ + proc_macro2_dep, + syn_dep, + ], + native: true, +) + +attrs_dep = declare_dependency( + link_with: _attrs_rs, +) + +meson.override_dependency('attrs-0.2-rs', attrs_dep, native: true) From 60c96a8775c163383043d4ece6065dcb8f940856 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Jul 2025 10:50:58 +0200 Subject: [PATCH 06/29] rust: qemu-macros: switch #[property] parsing to use combinators Since we are going to add more attribute parsing for high-level migration state macros, use the attrs crate instead of a handwritten parser for device properties as well. Signed-off-by: Paolo Bonzini --- rust/Cargo.lock | 11 +++++ rust/qemu-macros/src/lib.rs | 86 ++++++++++++++--------------------- rust/qemu-macros/src/tests.rs | 8 ++-- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index eea928621a..8315f98c46 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -14,6 +14,16 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d" +[[package]] +name = "attrs" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "bilge" version = "0.2.0" @@ -188,6 +198,7 @@ dependencies = [ name = "qemu_macros" version = "0.1.0" dependencies = [ + "attrs", "proc-macro2", "quote", "syn", diff --git a/rust/qemu-macros/src/lib.rs b/rust/qemu-macros/src/lib.rs index 830b432698..7ab1806177 100644 --- a/rust/qemu-macros/src/lib.rs +++ b/rust/qemu-macros/src/lib.rs @@ -3,10 +3,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later use proc_macro::TokenStream; -use quote::{quote, quote_spanned, ToTokens}; +use quote::{quote, quote_spanned}; use syn::{ - parse::Parse, parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, - token::Comma, Data, DeriveInput, Error, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, + parse::{Parse, ParseStream}, + parse_macro_input, parse_quote, + punctuated::Punctuated, + spanned::Spanned, + token::Comma, + Attribute, Data, DeriveInput, Error, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, Variant, }; mod bits; @@ -159,61 +163,37 @@ enum DevicePropertyName { Str(syn::LitStr), } -#[derive(Debug)] +impl Parse for DevicePropertyName { + fn parse(input: ParseStream<'_>) -> syn::Result { + let lo = input.lookahead1(); + if lo.peek(syn::LitStr) { + Ok(Self::Str(input.parse()?)) + } else if lo.peek(syn::LitCStr) { + Ok(Self::CStr(input.parse()?)) + } else { + Err(lo.error()) + } + } +} + +#[derive(Default, Debug)] struct DeviceProperty { rename: Option, defval: Option, } -impl Parse for DeviceProperty { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let _: syn::Token![#] = input.parse()?; - let bracketed; - _ = syn::bracketed!(bracketed in input); - let attribute = bracketed.parse::()?; - debug_assert_eq!(&attribute.to_string(), "property"); - let mut retval = Self { - rename: None, - defval: None, - }; - let content; - _ = syn::parenthesized!(content in bracketed); - while !content.is_empty() { - let value: syn::Ident = content.parse()?; - if value == "rename" { - let _: syn::Token![=] = content.parse()?; - if retval.rename.is_some() { - return Err(syn::Error::new( - value.span(), - "`rename` can only be used at most once", - )); - } - if content.peek(syn::LitStr) { - retval.rename = Some(DevicePropertyName::Str(content.parse::()?)); - } else { - retval.rename = - Some(DevicePropertyName::CStr(content.parse::()?)); - } - } else if value == "default" { - let _: syn::Token![=] = content.parse()?; - if retval.defval.is_some() { - return Err(syn::Error::new( - value.span(), - "`default` can only be used at most once", - )); - } - retval.defval = Some(content.parse()?); - } else { - return Err(syn::Error::new( - value.span(), - format!("unrecognized field `{value}`"), - )); - } +impl DeviceProperty { + fn parse_from(&mut self, a: &Attribute) -> syn::Result<()> { + use attrs::{set, with, Attrs}; + let mut parser = Attrs::new(); + parser.once("rename", with::eq(set::parse(&mut self.rename))); + parser.once("default", with::eq(set::parse(&mut self.defval))); + a.parse_args_with(&mut parser) + } - if !content.is_empty() { - let _: syn::Token![,] = content.parse()?; - } - } + fn parse(a: &Attribute) -> syn::Result { + let mut retval = Self::default(); + retval.parse_from(a)?; Ok(retval) } } @@ -235,7 +215,7 @@ fn derive_device_or_error(input: DeriveInput) -> Result, Error>>()?; let name = &input.ident; diff --git a/rust/qemu-macros/src/tests.rs b/rust/qemu-macros/src/tests.rs index 9ab7eab7f3..00a106612f 100644 --- a/rust/qemu-macros/src/tests.rs +++ b/rust/qemu-macros/src/tests.rs @@ -60,7 +60,7 @@ fn test_derive_device() { migrate_clock: bool, } }, - "unrecognized field `defalt`" + "Expected one of `default` or `rename`" ); // Check that repeated attributes are not allowed: derive_compile_fail!( @@ -73,7 +73,8 @@ fn test_derive_device() { migrate_clock: bool, } }, - "`rename` can only be used at most once" + "Duplicate argument", + "Already used here", ); derive_compile_fail!( derive_device_or_error, @@ -85,7 +86,8 @@ fn test_derive_device() { migrate_clock: bool, } }, - "`default` can only be used at most once" + "Duplicate argument", + "Already used here", ); // Check that the field name is preserved when `rename` isn't used: derive_compile!( From a530a8d4ac39d04dc0095b1cdb88867146445706 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:09 +0800 Subject: [PATCH 07/29] subprojects: Update .gitignore for proc-macro2 and syn Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-2-zhao1.liu@intel.com --- subprojects/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 983c4c1549..38e949640f 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -17,7 +17,7 @@ /libc-0.2.162 /proc-macro-error-1.0.4 /proc-macro-error-attr-1.0.4 -/proc-macro2-1.0.84 +/proc-macro2-1.0.95 /quote-1.0.36 /syn-2.0.66 /unicode-ident-1.0.12 From d935f0b8e17153e1dcfe93e7660bfd07693b513e Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:10 +0800 Subject: [PATCH 08/29] subprojects: Ignore .wraplock file generated by meson v1.9.0 The .wraplock file is automatically generated by meson v1.9.0 (the related issue: https://github.com/mesonbuild/meson/issues/14948). Ignore it for now. Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-3-zhao1.liu@intel.com --- subprojects/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 38e949640f..58a29f0120 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -21,3 +21,6 @@ /quote-1.0.36 /syn-2.0.66 /unicode-ident-1.0.12 + +# Workaround for Meson v1.9.0 https://github.com/mesonbuild/meson/issues/14948 +/.wraplock From 1bbac0ca88cdfd6ac019685a855c92831e3862e3 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:11 +0800 Subject: [PATCH 09/29] rust/qemu-macros: Fix Clippy's complaints about lambda parameter naming error: `rename` shadows a previous, unrelated binding --> qemu-macros/src/lib.rs:265:14 | 265 | |rename| -> Result { | ^^^^^^ | note: previous binding is here --> qemu-macros/src/lib.rs:245:30 | 245 | let DeviceProperty { rename, defval } = prop; | ^^^^^^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated = note: requested on the command line with `-D clippy::shadow-unrelated` Rename the lambda parameter to "prop_rename" to fix the above clippy error. Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-4-zhao1.liu@intel.com --- rust/qemu-macros/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/qemu-macros/src/lib.rs b/rust/qemu-macros/src/lib.rs index 7ab1806177..37e1b723bd 100644 --- a/rust/qemu-macros/src/lib.rs +++ b/rust/qemu-macros/src/lib.rs @@ -242,8 +242,8 @@ fn derive_device_or_error(input: DeriveInput) -> Result Result { - match rename { + |prop_rename| -> Result { + match prop_rename { DevicePropertyName::CStr(cstr_lit) => Ok(quote! { #cstr_lit }), DevicePropertyName::Str(str_lit) => { str_to_c_str!(str_lit.value(), str_lit.span()) From 35d7735f765adc4cf759b8ad221e8858ca5be9c5 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:12 +0800 Subject: [PATCH 10/29] rust/common/uninit: Fix Clippy's complaints about lifetime Clippy complains about the following cases and following its suggestion to fix these warnings. warning: the following explicit lifetimes could be elided: 'a --> common/src/uninit.rs:38:6 | 38 | impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> { | ^^ ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes = note: `#[warn(clippy::needless_lifetimes)]` on by default help: elide the lifetimes | 38 - impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> { 38 + impl Deref for MaybeUninitField<'_, T, U> { | warning: the following explicit lifetimes could be elided: 'a --> common/src/uninit.rs:49:6 | 49 | impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> { | ^^ ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes help: elide the lifetimes | 49 - impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> { 49 + impl DerefMut for MaybeUninitField<'_, T, U> { | warning: `common` (lib) generated 2 warnings (run `cargo clippy --fix --lib -p common` to apply 2 suggestions) Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-5-zhao1.liu@intel.com --- rust/common/src/uninit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/common/src/uninit.rs b/rust/common/src/uninit.rs index e7f9fcd2e3..8d021b1dfc 100644 --- a/rust/common/src/uninit.rs +++ b/rust/common/src/uninit.rs @@ -35,7 +35,7 @@ impl<'a, T, U> MaybeUninitField<'a, T, U> { } } -impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> { +impl Deref for MaybeUninitField<'_, T, U> { type Target = MaybeUninit; fn deref(&self) -> &MaybeUninit { @@ -46,7 +46,7 @@ impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> { } } -impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> { +impl DerefMut for MaybeUninitField<'_, T, U> { fn deref_mut(&mut self) -> &mut MaybeUninit { // SAFETY: self.child was obtained by dereferencing a valid mutable // reference; the content of the memory may be invalid or uninitialized From 51d736cd71a6515808b705010ec7e38695cb7a01 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 21 Sep 2025 00:05:13 +0800 Subject: [PATCH 11/29] rust/qdev: use addr_of! in QDevProp We want a &raw pointer, so unsafe { &_ } is not needed. Suggested-by: Zhao Liu Signed-off-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-6-zhao1.liu@intel.com --- rust/hw/core/src/qdev.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs index 71b9ef141c..3ee5b24262 100644 --- a/rust/hw/core/src/qdev.rs +++ b/rust/hw/core/src/qdev.rs @@ -6,7 +6,7 @@ use std::{ ffi::{c_int, c_void, CStr, CString}, - ptr::NonNull, + ptr::{addr_of, NonNull}, }; use chardev::Chardev; @@ -129,17 +129,17 @@ pub unsafe trait QDevProp { /// Use [`bindings::qdev_prop_bool`] for `bool`. unsafe impl QDevProp for bool { - const VALUE: *const bindings::PropertyInfo = unsafe { &bindings::qdev_prop_bool }; + const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_bool); } /// Use [`bindings::qdev_prop_uint64`] for `u64`. unsafe impl QDevProp for u64 { - const VALUE: *const bindings::PropertyInfo = unsafe { &bindings::qdev_prop_uint64 }; + const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_uint64); } /// Use [`bindings::qdev_prop_chr`] for [`chardev::CharBackend`]. unsafe impl QDevProp for chardev::CharBackend { - const VALUE: *const bindings::PropertyInfo = unsafe { &bindings::qdev_prop_chr }; + const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_chr); } /// Trait to define device properties. From bed2a37b2096e1d002f3b8e881c0f6eff863ff14 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 21 Sep 2025 00:05:14 +0800 Subject: [PATCH 12/29] rust/qdev: Refine the documentation for QDevProp trait Refine the documentation to clarify: * `unsfae` requires that `VALUE` must be valid. * using `*const` instead of `&` because the latter will cause compiler error. Signed-off-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-7-zhao1.liu@intel.com --- rust/hw/core/src/qdev.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs index 3ee5b24262..2735e2b2c1 100644 --- a/rust/hw/core/src/qdev.rs +++ b/rust/hw/core/src/qdev.rs @@ -109,9 +109,16 @@ unsafe extern "C" fn rust_resettable_exit_fn( /// /// # Safety /// -/// This trait is marked as `unsafe` because currently having a `const` refer to -/// an `extern static` as a reference instead of a raw pointer results in this -/// compiler error: +/// This trait is marked as `unsafe` because `VALUE` must be a valid raw +/// reference to a [`bindings::PropertyInfo`]. +/// +/// Note we could not use a regular reference: +/// +/// ```text +/// const VALUE: &bindings::PropertyInfo = ... +/// ``` +/// +/// because this results in the following compiler error: /// /// ```text /// constructing invalid value: encountered reference to `extern` static in `const` @@ -119,7 +126,7 @@ unsafe extern "C" fn rust_resettable_exit_fn( /// /// This is because the compiler generally might dereference a normal reference /// during const evaluation, but not in this case (if it did, it'd need to -/// dereference the raw pointer so this would fail to compile). +/// dereference the raw pointer so using a `*const` would also fail to compile). /// /// It is the implementer's responsibility to provide a valid /// [`bindings::PropertyInfo`] pointer for the trait implementation to be safe. From b4221e88a9a497c3d72c4dfad1bcc12468f3fd01 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:15 +0800 Subject: [PATCH 13/29] rust/qdev: Support property info for more common types Add a helper macro to implement QDevProp trait for u8/u16/u32/usize/i32 /i64. Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-8-zhao1.liu@intel.com --- rust/hw/core/src/qdev.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs index 2735e2b2c1..85422e0379 100644 --- a/rust/hw/core/src/qdev.rs +++ b/rust/hw/core/src/qdev.rs @@ -134,20 +134,24 @@ pub unsafe trait QDevProp { const VALUE: *const bindings::PropertyInfo; } -/// Use [`bindings::qdev_prop_bool`] for `bool`. -unsafe impl QDevProp for bool { - const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_bool); +macro_rules! impl_qdev_prop { + ($type:ty,$info:ident) => { + unsafe impl $crate::qdev::QDevProp for $type { + const VALUE: *const $crate::bindings::PropertyInfo = + addr_of!($crate::bindings::$info); + } + }; } -/// Use [`bindings::qdev_prop_uint64`] for `u64`. -unsafe impl QDevProp for u64 { - const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_uint64); -} - -/// Use [`bindings::qdev_prop_chr`] for [`chardev::CharBackend`]. -unsafe impl QDevProp for chardev::CharBackend { - const VALUE: *const bindings::PropertyInfo = addr_of!(bindings::qdev_prop_chr); -} +impl_qdev_prop!(bool, qdev_prop_bool); +impl_qdev_prop!(u8, qdev_prop_uint8); +impl_qdev_prop!(u16, qdev_prop_uint16); +impl_qdev_prop!(u32, qdev_prop_uint32); +impl_qdev_prop!(u64, qdev_prop_uint64); +impl_qdev_prop!(usize, qdev_prop_usize); +impl_qdev_prop!(i32, qdev_prop_int32); +impl_qdev_prop!(i64, qdev_prop_int64); +impl_qdev_prop!(chardev::CharBackend, qdev_prop_chr); /// Trait to define device properties. /// From 9686aa9a05d9ef25c13ddc0af0123e2fc569b0ac Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:16 +0800 Subject: [PATCH 14/29] rust/qdev: Support bit property in #property macro Add BIT_INFO to QDevProp trait, so that bit related property info could be bound to u32 & u64. Then add "bit=*" field in #property attributes macro to allow device to configure bit property. In addtion, convert the #property field parsing from `if-else` pattern to `match` pattern, to help readability. And note, the `bitnr` member of `Property` struct is generated by manual TokenStream construction, instead of conditional repetition (like #(bitnr: #bitnr,)?) since `quote` doesn't support this. In addtion, rename VALUE member of QDevProp trait to BASE_INFO. And update the test cases about qdev property. Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-9-zhao1.liu@intel.com --- rust/hw/core/src/qdev.rs | 19 ++++++++++++------- rust/qemu-macros/src/lib.rs | 18 +++++++++++++++--- rust/qemu-macros/src/tests.rs | 8 +++++--- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs index 85422e0379..9c82e1716c 100644 --- a/rust/hw/core/src/qdev.rs +++ b/rust/hw/core/src/qdev.rs @@ -109,8 +109,8 @@ unsafe extern "C" fn rust_resettable_exit_fn( /// /// # Safety /// -/// This trait is marked as `unsafe` because `VALUE` must be a valid raw -/// reference to a [`bindings::PropertyInfo`]. +/// This trait is marked as `unsafe` because `BASE_INFO` and `BIT_INFO` must be +/// valid raw references to [`bindings::PropertyInfo`]. /// /// Note we could not use a regular reference: /// @@ -131,14 +131,19 @@ unsafe extern "C" fn rust_resettable_exit_fn( /// It is the implementer's responsibility to provide a valid /// [`bindings::PropertyInfo`] pointer for the trait implementation to be safe. pub unsafe trait QDevProp { - const VALUE: *const bindings::PropertyInfo; + const BASE_INFO: *const bindings::PropertyInfo; + const BIT_INFO: *const bindings::PropertyInfo = { + panic!("invalid type for bit property"); + }; } macro_rules! impl_qdev_prop { - ($type:ty,$info:ident) => { + ($type:ty,$info:ident$(, $bit_info:ident)?) => { unsafe impl $crate::qdev::QDevProp for $type { - const VALUE: *const $crate::bindings::PropertyInfo = + const BASE_INFO: *const $crate::bindings::PropertyInfo = addr_of!($crate::bindings::$info); + $(const BIT_INFO: *const $crate::bindings::PropertyInfo = + addr_of!($crate::bindings::$bit_info);)? } }; } @@ -146,8 +151,8 @@ macro_rules! impl_qdev_prop { impl_qdev_prop!(bool, qdev_prop_bool); impl_qdev_prop!(u8, qdev_prop_uint8); impl_qdev_prop!(u16, qdev_prop_uint16); -impl_qdev_prop!(u32, qdev_prop_uint32); -impl_qdev_prop!(u64, qdev_prop_uint64); +impl_qdev_prop!(u32, qdev_prop_uint32, qdev_prop_bit); +impl_qdev_prop!(u64, qdev_prop_uint64, qdev_prop_bit64); impl_qdev_prop!(usize, qdev_prop_usize); impl_qdev_prop!(i32, qdev_prop_int32); impl_qdev_prop!(i64, qdev_prop_int64); diff --git a/rust/qemu-macros/src/lib.rs b/rust/qemu-macros/src/lib.rs index 37e1b723bd..3e21b67b47 100644 --- a/rust/qemu-macros/src/lib.rs +++ b/rust/qemu-macros/src/lib.rs @@ -179,6 +179,7 @@ impl Parse for DevicePropertyName { #[derive(Default, Debug)] struct DeviceProperty { rename: Option, + bitnr: Option, defval: Option, } @@ -187,6 +188,7 @@ impl DeviceProperty { use attrs::{set, with, Attrs}; let mut parser = Attrs::new(); parser.once("rename", with::eq(set::parse(&mut self.rename))); + parser.once("bit", with::eq(set::parse(&mut self.bitnr))); parser.once("default", with::eq(set::parse(&mut self.defval))); a.parse_args_with(&mut parser) } @@ -222,7 +224,11 @@ fn derive_device_or_error(input: DeriveInput) -> Result {{ @@ -252,14 +258,20 @@ fn derive_device_or_error(input: DeriveInput) -> Result::VALUE }; + let qdev_prop = if bitnr.is_none() { + quote! { <#field_ty as ::hwcore::QDevProp>::BASE_INFO } + } else { + quote! { <#field_ty as ::hwcore::QDevProp>::BIT_INFO } + }; + let bitnr = bitnr.unwrap_or(syn::Expr::Verbatim(quote! { 0 })); let set_default = defval.is_some(); let defval = defval.unwrap_or(syn::Expr::Verbatim(quote! { 0 })); properties_expanded.push(quote! { ::hwcore::bindings::Property { name: ::std::ffi::CStr::as_ptr(#prop_name), - info: #qdev_prop , + info: #qdev_prop, offset: ::core::mem::offset_of!(#name, #field_name) as isize, + bitnr: #bitnr, set_default: #set_default, defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: #defval as u64 }, ..::common::Zeroable::ZERO diff --git a/rust/qemu-macros/src/tests.rs b/rust/qemu-macros/src/tests.rs index 00a106612f..ec137132ae 100644 --- a/rust/qemu-macros/src/tests.rs +++ b/rust/qemu-macros/src/tests.rs @@ -60,7 +60,7 @@ fn test_derive_device() { migrate_clock: bool, } }, - "Expected one of `default` or `rename`" + "Expected one of `bit`, `default` or `rename`" ); // Check that repeated attributes are not allowed: derive_compile_fail!( @@ -106,8 +106,9 @@ fn test_derive_device() { const PROPERTIES: &'static [::hwcore::bindings::Property] = &[ ::hwcore::bindings::Property { name: ::std::ffi::CStr::as_ptr(c"migrate_clock"), - info: ::VALUE, + info: ::BASE_INFO, offset: ::core::mem::offset_of!(DummyState, migrate_clock) as isize, + bitnr: 0, set_default: true, defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: true as u64 }, ..::common::Zeroable::ZERO @@ -133,8 +134,9 @@ fn test_derive_device() { const PROPERTIES: &'static [::hwcore::bindings::Property] = &[ ::hwcore::bindings::Property { name: ::std::ffi::CStr::as_ptr(c"migrate-clk"), - info: ::VALUE, + info: ::BASE_INFO, offset: ::core::mem::offset_of!(DummyState, migrate_clock) as isize, + bitnr: 0, set_default: true, defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: true as u64 }, ..::common::Zeroable::ZERO From a8f080215f79d211c4be0f896ad5f32dbc3b7c03 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:17 +0800 Subject: [PATCH 15/29] rust/qdev: Test bit property for #property There's a diference between Rust and C: Though C macro (e.g., DEFINE_PROP_BIT or DEFINE_PROP_BIT64) always requires default value, Rust side allows to omit this "default" field in #property, and provides a default value ("0" - false) for this field. This minor difference does not break user habits and should be acceptable. Therefore, the test cases also cover this scenario. Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-10-zhao1.liu@intel.com --- rust/qemu-macros/src/tests.rs | 99 +++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/rust/qemu-macros/src/tests.rs b/rust/qemu-macros/src/tests.rs index ec137132ae..ac998d20e3 100644 --- a/rust/qemu-macros/src/tests.rs +++ b/rust/qemu-macros/src/tests.rs @@ -89,6 +89,19 @@ fn test_derive_device() { "Duplicate argument", "Already used here", ); + derive_compile_fail!( + derive_device_or_error, + quote! { + #[repr(C)] + #[derive(Device)] + struct DummyState { + #[property(bit = 0, bit = 1)] + flags: u32, + } + }, + "Duplicate argument", + "Already used here", + ); // Check that the field name is preserved when `rename` isn't used: derive_compile!( derive_device_or_error, @@ -145,6 +158,92 @@ fn test_derive_device() { } } ); + // Check that `bit` value is used for the bit property without default + // value (note: though C macro (e.g., DEFINE_PROP_BIT) always requires + // default value, Rust side allows to default this field to "0"): + derive_compile!( + derive_device_or_error, + quote! { + #[repr(C)] + #[derive(Device)] + pub struct DummyState { + parent: ParentField, + #[property(bit = 3)] + flags: u32, + } + }, + quote! { + unsafe impl ::hwcore::DevicePropertiesImpl for DummyState { + const PROPERTIES: &'static [::hwcore::bindings::Property] = &[ + ::hwcore::bindings::Property { + name: ::std::ffi::CStr::as_ptr(c"flags"), + info: ::BIT_INFO, + offset: ::core::mem::offset_of!(DummyState, flags) as isize, + bitnr: 3, + set_default: false, + defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: 0 as u64 }, + ..::common::Zeroable::ZERO + } + ]; + } + } + ); + // Check that `bit` value is used for the bit property when used: + derive_compile!( + derive_device_or_error, + quote! { + #[repr(C)] + #[derive(Device)] + pub struct DummyState { + parent: ParentField, + #[property(bit = 3, default = true)] + flags: u32, + } + }, + quote! { + unsafe impl ::hwcore::DevicePropertiesImpl for DummyState { + const PROPERTIES: &'static [::hwcore::bindings::Property] = &[ + ::hwcore::bindings::Property { + name: ::std::ffi::CStr::as_ptr(c"flags"), + info: ::BIT_INFO, + offset: ::core::mem::offset_of!(DummyState, flags) as isize, + bitnr: 3, + set_default: true, + defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: true as u64 }, + ..::common::Zeroable::ZERO + } + ]; + } + } + ); + // Check that `bit` value is used for the bit property with rename when used: + derive_compile!( + derive_device_or_error, + quote! { + #[repr(C)] + #[derive(Device)] + pub struct DummyState { + parent: ParentField, + #[property(rename = "msi", bit = 3, default = false)] + flags: u64, + } + }, + quote! { + unsafe impl ::hwcore::DevicePropertiesImpl for DummyState { + const PROPERTIES: &'static [::hwcore::bindings::Property] = &[ + ::hwcore::bindings::Property { + name: ::std::ffi::CStr::as_ptr(c"msi"), + info: ::BIT_INFO, + offset: ::core::mem::offset_of!(DummyState, flags) as isize, + bitnr: 3, + set_default: true, + defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: false as u64 }, + ..::common::Zeroable::ZERO + } + ]; + } + } + ); } #[test] From 4f09cf54faad32d41dfb5ccdd4c0e7871b636274 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:18 +0800 Subject: [PATCH 16/29] rust/hpet: Clean up type mismatch for num_timers property Now `num_timers` is `usize` other than `u8`. Although the type field in `declare_properties` macro hasn't been used, it's better to explicitly point this out and clean up this before doing other property work. Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-11-zhao1.liu@intel.com --- rust/hw/timer/hpet/src/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs index 3cfbe9c32b..fce7541557 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -909,7 +909,7 @@ declare_properties! { HPETState, num_timers, unsafe { &qdev_prop_usize }, - u8, + usize, default = HPET_MIN_TIMERS ), define_property!( From b160ebadc196091ca7abe00471f49fdc6bb8faf6 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:19 +0800 Subject: [PATCH 17/29] rust/hpet: Convert qdev properties to #property macro Convert HPET's properties to #property macro: * num_timers: usize property. * flags: u32 bit property. * int_route_cap: u32 property. * hpet_offset_saved: bool property. Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-12-zhao1.liu@intel.com --- rust/hw/timer/hpet/src/device.rs | 55 ++++---------------------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs index fce7541557..86638c0766 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -13,9 +13,8 @@ use std::{ use bql::{BqlCell, BqlRefCell}; use common::{bitops::IntegerExt, uninit_field_mut}; use hwcore::{ - bindings::{qdev_prop_bit, qdev_prop_bool, qdev_prop_uint32, qdev_prop_usize}, - declare_properties, define_property, DeviceImpl, DeviceMethods, DeviceState, InterruptSource, - Property, ResetType, ResettablePhasesImpl, SysBusDevice, SysBusDeviceImpl, SysBusDeviceMethods, + DeviceImpl, DeviceMethods, DeviceState, InterruptSource, ResetType, ResettablePhasesImpl, + SysBusDevice, SysBusDeviceImpl, SysBusDeviceMethods, }; use migration::{ self, impl_vmstate_struct, vmstate_fields, vmstate_of, vmstate_subsections, vmstate_validate, @@ -520,7 +519,7 @@ impl HPETTimer { /// HPET Event Timer Block Abstraction #[repr(C)] -#[derive(qom::Object)] +#[derive(qom::Object, hwcore::Device)] pub struct HPETState { parent_obj: ParentField, iomem: MemoryRegion, @@ -540,10 +539,12 @@ pub struct HPETState { // Internal state /// Capabilities that QEMU HPET supports. /// bit 0: MSI (or FSB) support. + #[property(rename = "msi", bit = HPET_FLAG_MSI_SUPPORT_SHIFT as u8, default = false)] flags: u32, /// Offset of main counter relative to qemu clock. hpet_offset: BqlCell, + #[property(rename = "hpet-offset-saved", default = true)] hpet_offset_saved: bool, irqs: [InterruptSource; HPET_NUM_IRQ_ROUTES], @@ -555,11 +556,13 @@ pub struct HPETState { /// the timers' interrupt can be routed, and is encoded in the /// bits 32:64 of timer N's config register: #[doc(alias = "intcap")] + #[property(rename = "hpet-intcap", default = 0)] int_route_cap: u32, /// HPET timer array managed by this timer block. #[doc(alias = "timer")] timers: [BqlRefCell; HPET_MAX_TIMERS], + #[property(rename = "timers", default = HPET_MIN_TIMERS)] num_timers: usize, num_timers_save: BqlCell, @@ -901,44 +904,6 @@ impl ObjectImpl for HPETState { const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::; } -// TODO: Make these properties user-configurable! -declare_properties! { - HPET_PROPERTIES, - define_property!( - c"timers", - HPETState, - num_timers, - unsafe { &qdev_prop_usize }, - usize, - default = HPET_MIN_TIMERS - ), - define_property!( - c"msi", - HPETState, - flags, - unsafe { &qdev_prop_bit }, - u32, - bit = HPET_FLAG_MSI_SUPPORT_SHIFT as u8, - default = false, - ), - define_property!( - c"hpet-intcap", - HPETState, - int_route_cap, - unsafe { &qdev_prop_uint32 }, - u32, - default = 0 - ), - define_property!( - c"hpet-offset-saved", - HPETState, - hpet_offset_saved, - unsafe { &qdev_prop_bool }, - bool, - default = true - ), -} - static VMSTATE_HPET_RTC_IRQ_LEVEL: VMStateDescription = VMStateDescriptionBuilder::::new() .name(c"hpet/rtc_irq_level") @@ -1001,12 +966,6 @@ const VMSTATE_HPET: VMStateDescription = )) .build(); -// SAFETY: HPET_PROPERTIES is a valid Property array constructed with the -// hwcore::declare_properties macro. -unsafe impl hwcore::DevicePropertiesImpl for HPETState { - const PROPERTIES: &'static [Property] = &HPET_PROPERTIES; -} - impl DeviceImpl for HPETState { const VMSTATE: Option> = Some(VMSTATE_HPET); const REALIZE: Option util::Result<()>> = Some(Self::realize); From 0a7fe8d407009840bee0e6d95005714ede51d0b8 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Sun, 21 Sep 2025 00:05:20 +0800 Subject: [PATCH 18/29] rust/qdev: Drop declare_properties & define_property macros After HPET's #property conversion, there's no use case for declare_properties & define_property. So get rid of them for now. In future, if there's something that #property really cannot resolve, they can be brought back. Reviewed-by: Manos Pitsidianakis Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20250920160520.3699591-13-zhao1.liu@intel.com --- rust/hw/core/src/qdev.rs | 53 ---------------------------------------- 1 file changed, 53 deletions(-) diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs index 9c82e1716c..a4493dbf01 100644 --- a/rust/hw/core/src/qdev.rs +++ b/rust/hw/core/src/qdev.rs @@ -248,59 +248,6 @@ impl DeviceClass { } } -#[macro_export] -macro_rules! define_property { - ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, bit = $bitnr:expr, default = $defval:expr$(,)*) => { - $crate::bindings::Property { - // use associated function syntax for type checking - name: ::std::ffi::CStr::as_ptr($name), - info: $prop, - offset: ::std::mem::offset_of!($state, $field) as isize, - bitnr: $bitnr, - set_default: true, - defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, - ..::common::zeroable::Zeroable::ZERO - } - }; - ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => { - $crate::bindings::Property { - // use associated function syntax for type checking - name: ::std::ffi::CStr::as_ptr($name), - info: $prop, - offset: ::std::mem::offset_of!($state, $field) as isize, - set_default: true, - defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, - ..::common::zeroable::Zeroable::ZERO - } - }; - ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => { - $crate::bindings::Property { - // use associated function syntax for type checking - name: ::std::ffi::CStr::as_ptr($name), - info: $prop, - offset: ::std::mem::offset_of!($state, $field) as isize, - set_default: false, - ..::common::zeroable::Zeroable::ZERO - } - }; -} - -#[macro_export] -macro_rules! declare_properties { - ($ident:ident, $($prop:expr),*$(,)*) => { - pub static $ident: [$crate::bindings::Property; { - let mut len = 0; - $({ - _ = stringify!($prop); - len += 1; - })* - len - }] = [ - $($prop),*, - ]; - }; -} - unsafe impl ObjectType for DeviceState { type Class = DeviceClass; const TYPE_NAME: &'static CStr = From db05b0d21ec1e0532cf5f5103ae6520a838d96f9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 19 Sep 2025 10:20:54 +0200 Subject: [PATCH 19/29] linux-user: avoid -Werror=int-in-bool-context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux-user is failing to compile on Fedora 43: ../linux-user/strace.c:57:66: error: enum constant in boolean context [-Werror=int-in-bool-context] 57 | #define FLAG_BASIC(V, M, N) { V, M | QEMU_BUILD_BUG_ON_ZERO(!(M)), N } The warning does not seem to be too useful and we could even disable it, but the workaround is simple in this case. Cc: qemu-stable@nongnu.org Cc: Richard Henderson Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 1233ebceb0..758c5d32b6 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -54,7 +54,7 @@ struct flags { }; /* No 'struct flags' element should have a zero mask. */ -#define FLAG_BASIC(V, M, N) { V, M | QEMU_BUILD_BUG_ON_ZERO(!(M)), N } +#define FLAG_BASIC(V, M, N) { V, M | QEMU_BUILD_BUG_ON_ZERO((M) == 0), N } /* common flags for all architectures */ #define FLAG_GENERIC_MASK(V, M) FLAG_BASIC(V, M, #V) From 62e82053fc676e9493dc2c2072352634b8cd655d Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:20 +0900 Subject: [PATCH 20/29] docs/devel: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Remove the instruction to call object_unparent(), and the exception of the "do not call object_unparent()" rule for instance_finalize(). Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-1-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- docs/devel/memory.rst | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/docs/devel/memory.rst b/docs/devel/memory.rst index 42d3ca29c4..f22146e56c 100644 --- a/docs/devel/memory.rst +++ b/docs/devel/memory.rst @@ -165,17 +165,14 @@ and finalized one by one. The order in which memory regions will be finalized is not guaranteed. If however the memory region is part of a dynamically allocated data -structure, you should call object_unparent() to destroy the memory region -before the data structure is freed. For an example see VFIOMSIXInfo -and VFIOQuirk in hw/vfio/pci.c. +structure, you should free the memory region in the instance_finalize +callback. For an example see VFIOMSIXInfo and VFIOQuirk in +hw/vfio/pci.c. You must not destroy a memory region as long as it may be in use by a device or CPU. In order to do this, as a general rule do not create or -destroy memory regions dynamically during a device's lifetime, and only -call object_unparent() in the memory region owner's instance_finalize -callback. The dynamically allocated data structure that contains the -memory region then should obviously be freed in the instance_finalize -callback as well. +destroy memory regions dynamically during a device's lifetime, and never +call object_unparent(). If you break this rule, the following situation can happen: @@ -201,9 +198,7 @@ this exception is rarely necessary, and therefore it is discouraged, but nevertheless it is used in a few places. For regions that "have no owner" (NULL is passed at creation time), the -machine object is actually used as the owner. Since instance_finalize is -never called for the machine object, you must never call object_unparent -on regions that have no owner, unless they are aliases or containers. +machine object is actually used as the owner. Overlapping regions and priority From e3ed862cabce6d8a12300b941243cb44e9cd40d1 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:21 +0900 Subject: [PATCH 21/29] vfio/pci: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the insntance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-2-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/vfio/pci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index d14e96b2f8..bc0b4c4d56 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2025,7 +2025,6 @@ static void vfio_bars_finalize(VFIOPCIDevice *vdev) vfio_region_finalize(&bar->region); if (bar->mr) { assert(bar->size); - object_unparent(OBJECT(bar->mr)); g_free(bar->mr); bar->mr = NULL; } @@ -2033,9 +2032,6 @@ static void vfio_bars_finalize(VFIOPCIDevice *vdev) if (vdev->vga) { vfio_vga_quirk_finalize(vdev); - for (i = 0; i < ARRAY_SIZE(vdev->vga->region); i++) { - object_unparent(OBJECT(&vdev->vga->region[i].mem)); - } g_free(vdev->vga); } } From f9ce08489424905ae4a70218fa35013fe88d54ed Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:22 +0900 Subject: [PATCH 22/29] hw/core/register: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-3-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/core/register.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/core/register.c b/hw/core/register.c index 8f63d9f227..3340df70b0 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -314,7 +314,6 @@ RegisterInfoArray *register_init_block64(DeviceState *owner, void register_finalize_block(RegisterInfoArray *r_array) { - object_unparent(OBJECT(&r_array->mem)); g_free(r_array->r); g_free(r_array); } From 15d91385422eb42321f49144554439c52b18953a Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:23 +0900 Subject: [PATCH 23/29] hv-balloon: hw/core/register: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-4-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/hyperv/hv-balloon.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c index 6dbcb2d9a2..2d6d7db4ee 100644 --- a/hw/hyperv/hv-balloon.c +++ b/hw/hyperv/hv-balloon.c @@ -1475,16 +1475,6 @@ static void hv_balloon_ensure_mr(HvBalloon *balloon) balloon->mr->align = memory_region_get_alignment(hostmem_mr); } -static void hv_balloon_free_mr(HvBalloon *balloon) -{ - if (!balloon->mr) { - return; - } - - object_unparent(OBJECT(balloon->mr)); - g_clear_pointer(&balloon->mr, g_free); -} - static void hv_balloon_vmdev_realize(VMBusDevice *vdev, Error **errp) { ERRP_GUARD(); @@ -1580,7 +1570,7 @@ static void hv_balloon_vmdev_reset(VMBusDevice *vdev) */ static void hv_balloon_unrealize_finalize_common(HvBalloon *balloon) { - hv_balloon_free_mr(balloon); + g_clear_pointer(&balloon->mr, g_free); balloon->addr = 0; balloon->memslot_count = 0; From 0c6d897e38f5a6a864d6ae6dc42f521b84011107 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:24 +0900 Subject: [PATCH 24/29] hw/sd/sdhci: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-5-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/sd/sdhci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 3c897e54b7..89b595ce4a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1578,10 +1578,6 @@ static void sdhci_sysbus_finalize(Object *obj) { SDHCIState *s = SYSBUS_SDHCI(obj); - if (s->dma_mr) { - object_unparent(OBJECT(s->dma_mr)); - } - sdhci_uninitfn(s); } From 9b80f8a8e758b427501e6bcbcb114ae45ff68387 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:25 +0900 Subject: [PATCH 25/29] vfio: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-6-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/vfio/pci-quirks.c | 9 +-------- hw/vfio/region.c | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index c97606dbf1..b5da6afbf5 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1159,15 +1159,12 @@ void vfio_vga_quirk_exit(VFIOPCIDevice *vdev) void vfio_vga_quirk_finalize(VFIOPCIDevice *vdev) { - int i, j; + int i; for (i = 0; i < ARRAY_SIZE(vdev->vga->region); i++) { while (!QLIST_EMPTY(&vdev->vga->region[i].quirks)) { VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga->region[i].quirks); QLIST_REMOVE(quirk, next); - for (j = 0; j < quirk->nr_mem; j++) { - object_unparent(OBJECT(&quirk->mem[j])); - } g_free(quirk->mem); g_free(quirk->data); g_free(quirk); @@ -1207,14 +1204,10 @@ void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr) void vfio_bar_quirk_finalize(VFIOPCIDevice *vdev, int nr) { VFIOBAR *bar = &vdev->bars[nr]; - int i; while (!QLIST_EMPTY(&bar->quirks)) { VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); QLIST_REMOVE(quirk, next); - for (i = 0; i < quirk->nr_mem; i++) { - object_unparent(OBJECT(&quirk->mem[i])); - } g_free(quirk->mem); g_free(quirk->data); g_free(quirk); diff --git a/hw/vfio/region.c b/hw/vfio/region.c index d04c57db63..b165ab0b93 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -365,12 +365,9 @@ void vfio_region_finalize(VFIORegion *region) for (i = 0; i < region->nr_mmaps; i++) { if (region->mmaps[i].mmap) { munmap(region->mmaps[i].mmap, region->mmaps[i].size); - object_unparent(OBJECT(®ion->mmaps[i].mem)); } } - object_unparent(OBJECT(region->mem)); - g_free(region->mem); g_free(region->mmaps); From 46a8624fa7d116989389867f534b07ee562ebb1e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 24 Sep 2025 13:37:26 +0900 Subject: [PATCH 26/29] hw/xen: Do not unparent in instance_finalize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children are automatically unparented so manually unparenting is unnecessary. Worse, automatic unparenting happens before the instance_finalize() callback of the parent gets called, so object_unparent() calls in the callback will refer to objects that are already unparented, which is semantically incorrect. Signed-off-by: Akihiko Odaki Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250924-use-v4-7-07c6c598f53d@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini --- hw/xen/xen_pt_msi.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index 09cca4eecb..e9ba17317a 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -637,14 +637,5 @@ void xen_pt_msix_unmap(XenPCIPassthroughState *s) void xen_pt_msix_delete(XenPCIPassthroughState *s) { - XenPTMSIX *msix = s->msix; - - if (!msix) { - return; - } - - object_unparent(OBJECT(&msix->mmio)); - - g_free(s->msix); - s->msix = NULL; + g_clear_pointer(&s->msix, g_free); } From 1f64df25477eff72779b000588cb821c654f26b7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Sep 2025 12:45:21 +0200 Subject: [PATCH 27/29] docs/code-provenance: clarify scope very early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AI policy in QEMU is not about content generators, it is about generated content. Other uses are explicitly not covered. Rename the policy and clarify its scope in the TL;DR section, as a matter of convenience to the reader. Reviewed-by: Daniel P. Berrangé Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- docs/devel/code-provenance.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/devel/code-provenance.rst b/docs/devel/code-provenance.rst index b5aae2e253..dc3524ac17 100644 --- a/docs/devel/code-provenance.rst +++ b/docs/devel/code-provenance.rst @@ -285,8 +285,8 @@ Such tools are acceptable to use, provided there is clearly defined copyright and licensing for their output. Note in particular the caveats applying to AI content generators below. -Use of AI content generators -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use of AI-generated content +~~~~~~~~~~~~~~~~~~~~~~~~~~~ TL;DR: @@ -294,6 +294,10 @@ TL;DR: believed to include or derive from AI generated content. This includes ChatGPT, Claude, Copilot, Llama and similar tools.** + **This policy does not apply to other uses of AI, such as researching APIs + or algorithms, static analysis, or debugging, provided their output is not + included in contributions.** + The increasing prevalence of AI-assisted software development results in a number of difficult legal questions and risks for software projects, including QEMU. Of particular concern is content generated by `Large Language Models @@ -322,10 +326,6 @@ The QEMU project thus requires that contributors refrain from using AI content generators on patches intended to be submitted to the project, and will decline any contribution if use of AI is either known or suspected. -This policy does not apply to other uses of AI, such as researching APIs or -algorithms, static analysis, or debugging, provided their output is not to be -included in contributions. - Examples of tools impacted by this policy includes GitHub's CoPilot, OpenAI's ChatGPT, Anthropic's Claude, and Meta's Code Llama, and code/content generation agents which are built on top of such tools. From 9ceb9b42c8f0f7ea6a4975e67405cfebee249ba8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Sep 2025 12:51:37 +0200 Subject: [PATCH 28/29] docs/code-provenance: make the exception process more prominent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU's AI generated content policy does not flesh out the exception process yet. Do it, while at the same time keeping things informal: ask contributors to explain what they would like to use AI for, and let them reach a consensus with the project on why it is credible to claim DCO compliance in that specific scenario. In other words, exceptions do not "solve the AI copyright problem". They take a position that a reasonable contributor could have, and assert that we're comfortable with the argument. Suggested-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- docs/devel/code-provenance.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/devel/code-provenance.rst b/docs/devel/code-provenance.rst index dc3524ac17..6968d54be8 100644 --- a/docs/devel/code-provenance.rst +++ b/docs/devel/code-provenance.rst @@ -331,8 +331,13 @@ ChatGPT, Anthropic's Claude, and Meta's Code Llama, and code/content generation agents which are built on top of such tools. This policy may evolve as AI tools mature and the legal situation is -clarifed. In the meanwhile, requests for exceptions to this policy will be -evaluated by the QEMU project on a case by case basis. To be granted an -exception, a contributor will need to demonstrate clarity of the license and -copyright status for the tool's output in relation to its training model and -code, to the satisfaction of the project maintainers. +clarified. + +Exceptions +^^^^^^^^^^ + +The QEMU project welcomes discussion on any exceptions to this policy, +or more general revisions. This can be done by contacting the qemu-devel +mailing list with details of a proposed tool, model, usage scenario, etc. +that is beneficial to QEMU, while still mitigating issues around compliance +with the DCO. After discussion, any exception will be listed below. From cd64320e1e27168d3796a847bbfde66c8b1116f9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Sep 2025 13:14:01 +0200 Subject: [PATCH 29/29] docs/code-provenance: AI exceptions are in addition to DCO Using phrasing from https://openinfra.org/legal/ai-policy (with just "commit" replaced by "submission", because we do not submit changes as commits but rather emails), clarify that the contributor remains responsible for its copyright or license status. [This is not my preferred phrasing. I would prefer something lighter like "the "Signed-off-by" label in the contribution gives the author responsibility". But for the sake of not reinventing the wheel I am keeping the exact words from the OpenInfra policy.] Reviewed-by: Peter Maydell Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- docs/devel/code-provenance.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/devel/code-provenance.rst b/docs/devel/code-provenance.rst index 6968d54be8..8cdc56f664 100644 --- a/docs/devel/code-provenance.rst +++ b/docs/devel/code-provenance.rst @@ -341,3 +341,9 @@ or more general revisions. This can be done by contacting the qemu-devel mailing list with details of a proposed tool, model, usage scenario, etc. that is beneficial to QEMU, while still mitigating issues around compliance with the DCO. After discussion, any exception will be listed below. + +Exceptions do not remove the need for authors to comply with all other +requirements for contribution. In particular, the "Signed-off-by" +label in a patch submission is a statement that the author takes +responsibility for the entire contents of the patch, including any parts +that were generated or assisted by AI tools or other tools.