* qom: Do not unparent in instance_finalize
* linux-user: avoid -Werror=int-in-bool-context * docs: use the pyvenv version of Meson * rust: parse attributes using the attrs crate * rust: complete conversion of qdev properties to proc macro * docs: clarify AI-generated content policy -----BEGIN PGP SIGNATURE----- iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmjTnTgUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNYUwf9EpJbiCN8Qif9JU3XQEaOMDGTDO07 nMvn6RnRTFyn4iYzCc+pn6GFKWfJGZ6/cD9Qby7lyi3lHlhW8fLYbAcTXn1HoLNk lr/Ibmyaa8U2WP5u/QG+3dwn9zTgNFza3BFLguKrOhWjbv3ZL85xez29yChGgtYq sTUTigtl261JF4SvtOhzCMqUPo4wzqD0m0Vc/pjxrlgpHAb3rKf32Y6xPkNMVN84 81egbF0ZRtUbubjvGzPFstMdRcVBdrac5wnFPWum9GazuWwB4K8p2iBFdmuXMOhy NW6M8HP516zhoNk7bA5zQghxmhPWLXah4iA7MflAzLTI30s23TNIMCeJRw== =ug+J -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * qom: Do not unparent in instance_finalize * linux-user: avoid -Werror=int-in-bool-context * docs: use the pyvenv version of Meson * rust: parse attributes using the attrs crate * rust: complete conversion of qdev properties to proc macro * docs: clarify AI-generated content policy # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmjTnTgUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroNYUwf9EpJbiCN8Qif9JU3XQEaOMDGTDO07 # nMvn6RnRTFyn4iYzCc+pn6GFKWfJGZ6/cD9Qby7lyi3lHlhW8fLYbAcTXn1HoLNk # lr/Ibmyaa8U2WP5u/QG+3dwn9zTgNFza3BFLguKrOhWjbv3ZL85xez29yChGgtYq # sTUTigtl261JF4SvtOhzCMqUPo4wzqD0m0Vc/pjxrlgpHAb3rKf32Y6xPkNMVN84 # 81egbF0ZRtUbubjvGzPFstMdRcVBdrac5wnFPWum9GazuWwB4K8p2iBFdmuXMOhy # NW6M8HP516zhoNk7bA5zQghxmhPWLXah4iA7MflAzLTI30s23TNIMCeJRw== # =ug+J # -----END PGP SIGNATURE----- # gpg: Signature made Wed 24 Sep 2025 12:26:48 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [unknown] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # 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: (29 commits) docs/code-provenance: AI exceptions are in addition to DCO docs/code-provenance: make the exception process more prominent docs/code-provenance: clarify scope very early hw/xen: Do not unparent in instance_finalize() vfio: Do not unparent in instance_finalize() hw/sd/sdhci: Do not unparent in instance_finalize() hv-balloon: hw/core/register: Do not unparent in instance_finalize() hw/core/register: Do not unparent in instance_finalize() vfio/pci: Do not unparent in instance_finalize() docs/devel: Do not unparent in instance_finalize() linux-user: avoid -Werror=int-in-bool-context rust/qdev: Drop declare_properties & define_property macros rust/hpet: Convert qdev properties to #property macro rust/hpet: Clean up type mismatch for num_timers property rust/qdev: Test bit property for #property rust/qdev: Support bit property in #property macro rust/qdev: Support property info for more common types rust/qdev: Refine the documentation for QDevProp trait rust/qdev: use addr_of! in QDevProp rust/common/uninit: Fix Clippy's complaints about lifetime ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
95b9e0d2ad
33 changed files with 306 additions and 260 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,17 +326,24 @@ 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
11
rust/Cargo.lock
generated
11
rust/Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ _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".
|
||||
rust.doctest('rust-common-doctests',
|
||||
_common_rs,
|
||||
protocol: 'rust',
|
||||
dependencies: common_rs,
|
||||
suite: ['doc', 'rust'])
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ impl<'a, T, U> MaybeUninitField<'a, T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> {
|
||||
impl<T, U> Deref for MaybeUninitField<'_, T, U> {
|
||||
type Target = MaybeUninit<U>;
|
||||
|
||||
fn deref(&self) -> &MaybeUninit<U> {
|
||||
|
|
@ -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<T, U> DerefMut for MaybeUninitField<'_, T, U> {
|
||||
fn deref_mut(&mut self) -> &mut MaybeUninit<U> {
|
||||
// SAFETY: self.child was obtained by dereferencing a valid mutable
|
||||
// reference; the content of the memory may be invalid or uninitialized
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::{
|
||||
ffi::{c_int, c_void, CStr, CString},
|
||||
ptr::NonNull,
|
||||
ptr::{addr_of, NonNull},
|
||||
};
|
||||
|
||||
use chardev::Chardev;
|
||||
|
|
@ -109,9 +109,16 @@ unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
|
|||
///
|
||||
/// # 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 `BASE_INFO` and `BIT_INFO` must be
|
||||
/// valid raw references to [`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,28 +126,37 @@ unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
|
|||
///
|
||||
/// 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.
|
||||
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");
|
||||
};
|
||||
}
|
||||
|
||||
/// Use [`bindings::qdev_prop_bool`] for `bool`.
|
||||
unsafe impl QDevProp for bool {
|
||||
const VALUE: *const bindings::PropertyInfo = unsafe { &bindings::qdev_prop_bool };
|
||||
macro_rules! impl_qdev_prop {
|
||||
($type:ty,$info:ident$(, $bit_info:ident)?) => {
|
||||
unsafe impl $crate::qdev::QDevProp for $type {
|
||||
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);)?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Use [`bindings::qdev_prop_uint64`] for `u64`.
|
||||
unsafe impl QDevProp for u64 {
|
||||
const VALUE: *const bindings::PropertyInfo = unsafe { &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 };
|
||||
}
|
||||
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, 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);
|
||||
impl_qdev_prop!(chardev::CharBackend, qdev_prop_chr);
|
||||
|
||||
/// Trait to define device properties.
|
||||
///
|
||||
|
|
@ -232,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 =
|
||||
|
|
|
|||
|
|
@ -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<SysBusDevice>,
|
||||
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<u64>,
|
||||
#[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<HPETTimer>; HPET_MAX_TIMERS],
|
||||
#[property(rename = "timers", default = HPET_MIN_TIMERS)]
|
||||
num_timers: usize,
|
||||
num_timers_save: BqlCell<u8>,
|
||||
|
||||
|
|
@ -901,44 +904,6 @@ impl ObjectImpl for HPETState {
|
|||
const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
|
||||
}
|
||||
|
||||
// TODO: Make these properties user-configurable!
|
||||
declare_properties! {
|
||||
HPET_PROPERTIES,
|
||||
define_property!(
|
||||
c"timers",
|
||||
HPETState,
|
||||
num_timers,
|
||||
unsafe { &qdev_prop_usize },
|
||||
u8,
|
||||
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<HPETState> =
|
||||
VMStateDescriptionBuilder::<HPETState>::new()
|
||||
.name(c"hpet/rtc_irq_level")
|
||||
|
|
@ -1001,12 +966,6 @@ const VMSTATE_HPET: VMStateDescription<HPETState> =
|
|||
))
|
||||
.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<VMStateDescription<Self>> = Some(VMSTATE_HPET);
|
||||
const REALIZE: Option<fn(&Self) -> util::Result<()>> = Some(Self::realize);
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -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),)?
|
||||
|
|
|
|||
|
|
@ -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"] }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,39 @@ enum DevicePropertyName {
|
|||
Str(syn::LitStr),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
impl Parse for DevicePropertyName {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
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<DevicePropertyName>,
|
||||
bitnr: Option<syn::Expr>,
|
||||
defval: Option<syn::Expr>,
|
||||
}
|
||||
|
||||
impl Parse for DeviceProperty {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let _: syn::Token![#] = input.parse()?;
|
||||
let bracketed;
|
||||
_ = syn::bracketed!(bracketed in input);
|
||||
let attribute = bracketed.parse::<syn::Ident>()?;
|
||||
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::<syn::LitStr>()?));
|
||||
} else {
|
||||
retval.rename =
|
||||
Some(DevicePropertyName::CStr(content.parse::<syn::LitCStr>()?));
|
||||
}
|
||||
} 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("bit", with::eq(set::parse(&mut self.bitnr)));
|
||||
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<Self> {
|
||||
let mut retval = Self::default();
|
||||
retval.parse_from(a)?;
|
||||
Ok(retval)
|
||||
}
|
||||
}
|
||||
|
|
@ -235,14 +217,18 @@ fn derive_device_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream
|
|||
f.attrs
|
||||
.iter()
|
||||
.filter(|a| a.path().is_ident("property"))
|
||||
.map(|a| Ok((f.clone(), syn::parse2(a.to_token_stream())?)))
|
||||
.map(|a| Ok((f.clone(), DeviceProperty::parse(a)?)))
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
let name = &input.ident;
|
||||
let mut properties_expanded = vec![];
|
||||
|
||||
for (field, prop) in properties {
|
||||
let DeviceProperty { rename, defval } = prop;
|
||||
let DeviceProperty {
|
||||
rename,
|
||||
bitnr,
|
||||
defval,
|
||||
} = prop;
|
||||
let field_name = field.ident.unwrap();
|
||||
macro_rules! str_to_c_str {
|
||||
($value:expr, $span:expr) => {{
|
||||
|
|
@ -262,8 +248,8 @@ fn derive_device_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream
|
|||
|
||||
let prop_name = rename.map_or_else(
|
||||
|| str_to_c_str!(field_name.to_string(), field_name.span()),
|
||||
|rename| -> Result<proc_macro2::TokenStream, Error> {
|
||||
match rename {
|
||||
|prop_rename| -> Result<proc_macro2::TokenStream, Error> {
|
||||
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())
|
||||
|
|
@ -272,14 +258,20 @@ fn derive_device_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream
|
|||
},
|
||||
)?;
|
||||
let field_ty = field.ty.clone();
|
||||
let qdev_prop = quote! { <#field_ty as ::hwcore::QDevProp>::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
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ fn test_derive_device() {
|
|||
migrate_clock: bool,
|
||||
}
|
||||
},
|
||||
"unrecognized field `defalt`"
|
||||
"Expected one of `bit`, `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,21 @@ fn test_derive_device() {
|
|||
migrate_clock: bool,
|
||||
}
|
||||
},
|
||||
"`default` can only be used at most once"
|
||||
"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!(
|
||||
|
|
@ -104,8 +119,9 @@ fn test_derive_device() {
|
|||
const PROPERTIES: &'static [::hwcore::bindings::Property] = &[
|
||||
::hwcore::bindings::Property {
|
||||
name: ::std::ffi::CStr::as_ptr(c"migrate_clock"),
|
||||
info: <bool as ::hwcore::QDevProp>::VALUE,
|
||||
info: <bool as ::hwcore::QDevProp>::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
|
||||
|
|
@ -131,8 +147,9 @@ fn test_derive_device() {
|
|||
const PROPERTIES: &'static [::hwcore::bindings::Property] = &[
|
||||
::hwcore::bindings::Property {
|
||||
name: ::std::ffi::CStr::as_ptr(c"migrate-clk"),
|
||||
info: <bool as ::hwcore::QDevProp>::VALUE,
|
||||
info: <bool as ::hwcore::QDevProp>::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
|
||||
|
|
@ -141,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<DeviceState>,
|
||||
#[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: <u32 as ::hwcore::QDevProp>::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<DeviceState>,
|
||||
#[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: <u32 as ::hwcore::QDevProp>::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<DeviceState>,
|
||||
#[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: <u64 as ::hwcore::QDevProp>::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]
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -44,12 +44,15 @@ _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".
|
||||
rust.doctest('rust-util-rs-doctests',
|
||||
_util_rs,
|
||||
protocol: 'rust',
|
||||
dependencies: util_rs,
|
||||
suite: ['doc', 'rust']
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
6
subprojects/.gitignore
vendored
6
subprojects/.gitignore
vendored
|
|
@ -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
|
||||
|
|
@ -16,7 +17,10 @@
|
|||
/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
|
||||
|
||||
# Workaround for Meson v1.9.0 https://github.com/mesonbuild/meson/issues/14948
|
||||
/.wraplock
|
||||
|
|
|
|||
7
subprojects/attrs-0.2-rs.wrap
Normal file
7
subprojects/attrs-0.2-rs.wrap
Normal file
|
|
@ -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
|
||||
33
subprojects/packagefiles/attrs-0.2-rs/meson.build
Normal file
33
subprojects/packagefiles/attrs-0.2-rs/meson.build
Normal file
|
|
@ -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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue