Commit graph

33 commits

Author SHA1 Message Date
Paolo Bonzini
f117857b39 rust: replace c_str! with c"" literals
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-05-06 16:02:04 +02:00
Paolo Bonzini
b134a09ffa rust: remove offset_of replacement
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-05-06 16:02:04 +02:00
Zhao Liu
1998502196 rust/vmstate: Add unit test for vmstate_of macro
The vmstate has too many combinations of VMStateFlags and VMStateField.
Currently, the best way to test is to ensure that the Rust vmstate
definition is consistent with the (possibly corresponding) C version.

Add a unit test to cover some patterns accepted by vmstate_of macro,
which correspond to the following C version macros:
 * VMSTATE_U16
 * VMSTATE_UNUSED
 * VMSTATE_VARRAY_UINT16_UNSAFE
 * VMSTATE_VARRAY_MULTIPLY

Note: Because vmstate_info_* are defined in vmstate-types.c, it's
necessary to link libmigration to rust unit tests. In the future,
maybe it's possible to spilt libmigration from rust_qemu_api_objs.

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Link: https://lore.kernel.org/r/20250318130219.1799170-12-zhao1.liu@intel.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-03-21 12:56:00 +01:00
Paolo Bonzini
2d0050cbe2 rust: chardev: provide basic bindings to character devices
Most of the character device API is pretty simple, with "0 or -errno"
or "number of bytes or -errno" as the convention for return codes.
Add safe wrappers for the API to the CharBackend bindgen-generated
struct.

The API is not complete, but it covers the parts that are used
by the PL011 device, plus qemu_chr_fe_write which is needed to
implement the standard library Write trait.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-03-06 12:44:47 +01:00
Paolo Bonzini
f07a5674cf rust: qemu_api_macros: add Wrapper derive macro
Add a derive macro that makes it easy to peel off all the layers of
specialness (UnsafeCell, MaybeUninit, etc.) and just get a pointer
to the wrapped type; and likewise add them back starting from a
*mut.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-03-06 12:44:46 +01:00
Paolo Bonzini
8a420dd109 rust: add module to convert between success/-errno and io::Result
It is a common convention in QEMU to return a positive value in case of
success, and a negated errno value in case of error.  Unfortunately,
using errno portably in Rust is a bit complicated; on Unix the errno
values are supported natively by io::Error, but on Windows they are not;
so, use the libc crate.

This is a set of utility functions that are used by both chardev and
block layer bindings.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-02-25 16:18:08 +01:00
Zhao Liu
eadb83f9a3 rust: add bindings for timer
Add timer bindings to help handle idiomatic Rust callbacks.

Additionally, wrap QEMUClockType in ClockType binding to avoid unsafe
calls in device code.

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Link: https://lore.kernel.org/r/20250210030051.2562726-7-zhao1.liu@intel.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-02-13 12:51:34 +01:00
Paolo Bonzini
a22bd55ffd rust: chardev, qdev: add bindings to qdev_prop_set_chr
Because the argument to the function is an Owned<Chardev>, this also
adds an ObjectType implementation to Chardev.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-02-13 12:19:34 +01:00
Paolo Bonzini
590faa03ee rust: bindings for MemoryRegionOps
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-02-13 12:19:34 +01:00
Paolo Bonzini
7f65d4e58b rust: add a utility module for compile-time type checks
It is relatively common in the low-level qemu_api code to assert that
a field of a struct has a specific type; for example, it can be used
to ensure that the fields match what the qemu_api and C code expects
for safety.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-01-10 23:34:43 +01:00
Paolo Bonzini
122748c83d rust: fix --enable-debug-mutex
--feature is an option for cargo but not for rustc.

Reported-by: Bernhard Beschow <shentey@gmail.com>
Reviewed-by: Bernhard Beschow <shentey@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-01-07 10:18:53 +01:00
Paolo Bonzini
e05fbacd20 rust: qemu-api: add a module to wrap functions and zero-sized closures
One recurring issue when writing Rust bindings is how to convert a Rust
function ("fn" or "impl Fn") to a C function, and how to pass around
"self" to a C function that only takes a void*.

An easy solution would be to store on the heap a pair consisting of
a pointer to the Rust function and the pointer to "self", but it is
possible to do better.  If an "Fn" has zero size (that is, if it is a
zero-capture closures or a function pointer---which in turn includes all
methods), it is possible to build a generic Rust function that calls it
even if you only have the type; you don't need either the pointer to the
function itself (because the address of the code is part of the type)
or any closure data (because it has size zero).

Introduce a wrapper that provides the functionality of calling the
function given only its type.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-19 19:36:37 +01:00
Paolo Bonzini
d4873c5d4f bql: add a "mock" BQL for Rust unit tests
Right now, the stub BQL in stubs/iothread-lock.c always reports itself as
unlocked.  However, Rust would like to run its tests in an environment where
the BQL *is* locked.  Provide an extremely dirty function that flips the
return value of bql_is_locked() to true.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-19 19:36:37 +01:00
Paolo Bonzini
4aed0296b3 rust: rename qemu-api modules to follow C code a bit more
A full match would mean calling them qom::object and hw::core::qdev.  For now,
keep the names shorter but still a bit easier to find.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-19 19:36:37 +01:00
Paolo Bonzini
ab870fa106 rust: add a bit operation module
The bindgen supports `static inline` function binding since v0.64.0 as
an experimental feature (`--wrap-static-fns`), and stabilizes it after
v0.70.0.

But the oldest version of bindgen supported by QEMU is v0.60.1, so
there's no way to generate the binding for deposit64() which is `static
inline` (in include/qemu/bitops.h).

Instead, implement it by hand in Rust and make it available for all
unsigned types through an IntegerExt trait. Since it only involves bit
operations, the Rust version of the code is almost identical to the
original C version, but it applies to more types than just u64.

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Co-authored-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:49:26 +01:00
Paolo Bonzini
4ed4da164c rust: add bindings for interrupt sources
The InterruptSource bindings let us call qemu_set_irq() and sysbus_init_irq()
as safe code.

Interrupt sources, qemu_irq in C code, are pointers to IRQState objects.
They are QOM link properties and can be written to outside the control
of the device (i.e. from a shared reference); therefore they must be
interior-mutable in Rust.  Since thread-safety is provided by the BQL,
what we want here is the newly-introduced BqlCell.  A pointer to the
contents of the BqlCell (an IRQState**, or equivalently qemu_irq*)
is then passed to the C sysbus_init_irq function.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:49:26 +01:00
Paolo Bonzini
28d0ad3d42 rust: define prelude
Add a module that will contain frequently used traits and
occasionally structs.  They can be included quickly with
"use qemu_api::prelude::*".

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:49:26 +01:00
Paolo Bonzini
c596199f63 rust: cell: add BQL-enforcing RefCell variant
Similar to the existing BqlCell, introduce a custom interior mutability
primitive that resembles RefCell but accounts for QEMU's threading model.
Borrowing the RefCell requires proving that the BQL is held, and
attempting to access without the BQL is a runtime panic.

Almost all of the code was taken from Rust's standard library, while
removing unstable features and probably-unnecessary functionality that
amounts to 60% of the original code.  A lot of what's left is documentation,
as well as unit tests in the form of doctests.  These are not yet integrated
in "make check" but can be run with "cargo test --doc".

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:49:26 +01:00
Paolo Bonzini
8e194c0ea5 rust: cell: add BQL-enforcing Cell variant
QEMU objects usually have their pointer shared with the "outside
world" very early in their lifetime, for example when they create their
MemoryRegions.  Because at this point it is not valid anymore to
create a &mut reference to the device, individual parts of the
device struct must be made mutable in a controlled manner.

QEMU's Big Lock (BQL) effectively turns multi-threaded code into
single-threaded code while device code runs, as long as the BQL is not
released while the device is borrowed (because C code could sneak in and
mutate the device).  We can then introduce custom interior mutability primitives
that are semantically similar to the standard library's (single-threaded)
Cell and RefCell, but account for QEMU's threading model.  Accessing
the "BqlCell" or borrowing the "BqlRefCell" requires proving that the
BQL is held, and attempting to access without the BQL is a runtime panic,
similar to RefCell's already-borrowed panic.

With respect to naming I also considered omitting the "Bql" prefix or
moving it to the module, e.g.  qemu_api::bql::{Cell, RefCell}.  However,
this could easily lead to mistakes and confusion; for example rustc could
suggest the wrong import, leading to subtle bugs.

As a start introduce the an equivalent of Cell.  Almost all of the code
was taken from Rust's standard library, while removing unstable features
and probably-unnecessary functionality that constitute a large of the
original code.  A lot of what's left is documentation, as well as unit
tests in the form of doctests.  These are not yet integrated in "make
check" but can be run with "cargo test --doc".

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:49:25 +01:00
Paolo Bonzini
90868c3dce rust: cargo: store desired warning levels in workspace Cargo.toml
An extra benefit of workspaces is that they allow to place lint level
settings in a single Cargo.toml; the settings are then inherited by
packages in the workspace.

Correspondingly, teach rustc_args.py to get the unexpected_cfgs
configuration from the workspace Cargo.toml.

Note that it is still possible to allow or deny warnings per crate or
module, via the #![] attribute syntax.  The rust/qemu-api/src/bindings.rs
file is an example.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Paolo Bonzini
97ed1e9c8e rust: build: generate lint flags from Cargo.toml
Cargo.toml makes it possible to describe the desired lint level settings
in a nice format.  We can extend this to Meson-built crates, by teaching
rustc_args.py to fetch lint and --check-cfg arguments from Cargo.toml.
--check-cfg arguments come from the unexpected_cfgs lint as well as crate
features

Start with qemu-api, since it already has a [lints.rust] table and
an invocation of rustc_args.py.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Paolo Bonzini
1de82059aa rust: build: restrict --cfg generation to only required symbols
Parse the Cargo.toml file, looking for the unexpected_cfgs
configuration.  When generating --cfg options from the
config-host.h file, only use those that are included in the
configuration.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Paolo Bonzini
f3a6e9bc47 rust: build: move rustc_args.py invocation to qemu-api crate
Only qemu-api needs access to the symbols in config-host.h.  Remove
the temptation to use them elsewhere by limiting the --cfg arguments to
the qemu-api crate.

Per-crate invocation of the script will also be needed to add --check-cfg
options for each crate's features (when more complex, build-time
configurable devices are added in the future).

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Paolo Bonzini
cb7ada5409 rust: allow using build-root bindings.rs from cargo
Right now, using cargo with QEMU requires copying by hand the bindings.rs to the
source tree.  Instead, we can use an include file to escape the cage of cargo's
mandated source directory structure.

By running cargo within meson's "devenv" and adding a MESON_BUILD_ROOT
environment variable, it is easy for build.rs to find the file.  However, the
file must be symlinked into cargo's output directory for rust-analyzer to find
it.

Suggested-by: Junjie Mao <junjie.mao@hotmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Paolo Bonzini
8c28667503 rust: apply --cfg MESON to all crates
We might have more uses for --cfg MESON, even though right now it's only
qemu-api that has generated files.  Since we're going to add more flags
to the add_project_arguments calls for Rust, it makes sense to also add
--cfg MESON everywhere.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-12-10 18:44:06 +01:00
Junjie Mao
f351840088 rust: introduce alternative implementation of offset_of!
offset_of! was stabilized in Rust 1.77.0.  Use an alternative implemenation
that was found on the Rust forums, and whose author agreed to license as
MIT for use in QEMU.

The alternative allows only one level of field access, but apart
from this can be used just by replacing core::mem::offset_of! with
qemu_api::offset_of!.

The actual implementation of offset_of! is done in a declarative macro,
but for simplicity and to avoid introducing an extra level of indentation,
the trigger is a procedural macro #[derive(offsets)].

The procedural macro is perhaps a bit overengineered, but it helps
introducing some idioms that will be useful in the future as well.

Signed-off-by: Junjie Mao <junjie.mao@hotmail.com>
Co-developed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:16 +01:00
Paolo Bonzini
718e255f0a rust: introduce a c_str macro
This allows CStr constants to be defined easily on Rust 1.63.0, while
checking that there are no embedded NULs.  c"" literals were only
stabilized in Rust 1.77.0.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:16 +01:00
Manos Pitsidianakis
0a65e4124a rust: add definitions for vmstate
Add a new qemu_api module, `vmstate`. Declare a bunch of Rust
macros declared that are equivalent in spirit to the C macros in
include/migration/vmstate.h.

For example the Rust of equivalent of the C macro:

  VMSTATE_UINT32(field_name, struct_name)

is:

  vmstate_uint32!(field_name, StructName)

This breathtaking development will allow us to reach feature parity between
the Rust and C pl011 implementations.

Extracted from a patch by Manos Pitsidianakis
(https://lore.kernel.org/qemu-devel/20241024-rust-round-2-v1-4-051e7a25b978@linaro.org/).

Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:16 +01:00
Paolo Bonzini
6e50bde1e1 rust: provide safe wrapper for MaybeUninit::zeroed()
MaybeUninit::zeroed() is handy, but it introduces unsafe (and has a
pretty heavy syntax in general).  Introduce a trait that provides the
same functionality while staying within safe Rust.

In addition, MaybeUninit::zeroed() is not available as a "const"
function until Rust 1.75.0, so this also prepares for having handwritten
implementations of the trait until we can assume that version.

Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:16 +01:00
Paolo Bonzini
cde3c425d1 rust: build integration test for the qemu_api crate
Adjust the integration test to compile with a subset of QEMU object
files, and make it actually create an object of the class it defines.

Follow the Rust filesystem conventions, where tests go in tests/ if
they use the library in the same way any other code would.

Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:15 +01:00
Paolo Bonzini
7b72c7dd0d meson: pass rustc_args when building all crates
rustc_args is needed to smooth the difference in warnings between the various
versions of rustc.  Always include those arguments.

Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-11-05 14:18:15 +01:00
Manos Pitsidianakis
2b74dd9180 rust: add utility procedural macro crate
This commit adds a helper crate library, qemu-api-macros for derive (and
other procedural) macros to be used along qemu-api.

It needs to be a separate library because in Rust, procedural macros, or
macros that can generate arbitrary code, need to be special separate
compilation units.

Only one macro is introduced in this patch, #[derive(Object)]. It
generates a constructor to register a QOM TypeInfo on init and it must
be used on types that implement qemu_api::definitions::ObjectImpl trait.

Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Link: https://lore.kernel.org/r/dd645642406a6dc2060c6f3f17db2bc77ed67b59.1727961605.git.manos.pitsidianakis@linaro.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-10-11 12:32:17 +02:00
Manos Pitsidianakis
5a5110d290 rust: add crate to expose bindings and interfaces
Add rust/qemu-api, which exposes rust-bindgen generated FFI bindings and
provides some declaration macros for symbols visible to the rest of
QEMU.

Co-authored-by: Junjie Mao <junjie.mao@intel.com>
Co-authored-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Link: https://lore.kernel.org/r/0fb23fbe211761b263aacec03deaf85c0cc39995.1727961605.git.manos.pitsidianakis@linaro.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-10-11 12:32:17 +02:00