* [PULL 00/40] Rust changes for QEMU 9.2 soft freeze
@ 2024-11-04 17:26 Paolo Bonzini
2024-11-04 17:26 ` [PULL 01/40] qdev: make properties array "const" Paolo Bonzini
` (40 more replies)
0 siblings, 41 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
The following changes since commit 15195de6a93438be99fdf9a90992c4228527130d:
ci: enable rust in the Fedora system build job (2024-10-30 16:30:56 +0100)
are available in the Git repository at:
https://gitlab.com/bonzini/qemu.git tags/for-upstream-rust
for you to fetch changes up to d20feaa9a5af597bd20630d041e5dc7808612be1:
ci: enable rust in the Debian and Ubuntu system build job (2024-10-31 18:39:52 +0100)
----------------------------------------------------------------
* rust: cleanups
* rust: integration tests
* rust/pl011: add support for migration
* rust/pl011: add TYPE_PL011_LUMINARY device
* rust: add support for older compilers and bindgen
* rust: enable rust in the Debian, Fedora and Ubuntu system build job
----------------------------------------------------------------
This pull request enables Rust in QEMU's CI infrastructure, as a
first step towards collaborative development of Rust features. It matches
the plan that I mentioned last Thursday at
https://lore.kernel.org/qemu-devel/CABgObfb7=ZxgiasgB=dE8yV+bhd5-pd51n4qGpP8OFNBS3iMXQ@mail.gmail.com/.
There is a lot of new code in here that is specifically from me. Because of
the worry that new Rust code may introduce hidden technical debt, others have
reviewed all the Rust code in here, with the exception of the mostly trivial
https://lore.kernel.org/qemu-devel/20241025160209.194307-17-pbonzini@redhat.com/.
The changes focus on CI integration and compilation infrastructure:
* support for older Rust versions as found in QEMU's Debian bookworm and
Ubuntu CI targets. Workarounds for older Rust compiler versions are grouped
together for future cleanup.
* passing qtests with --enable-rust testing support: the pl011 code is closer
to parity with the C version, though still experimental.
Regarding toolchain compatibility: Michael Tokarev expressed some
doubts about supporting the old toolchain in Debian bookworm. However,
even trixie (currently in "testing") would require workarounds, mostly
due to lack of stable "offset_of!" support, so maintaining bookworm
compatibility seemed reasonable.
I am also working on a documentation patch that explains the more recent
features that would be nice to have.
Note that the Rust code still contains what is technically undefined
behavior (also known as "unsound code", i.e. unsafe code that does not
respect aliasing rules). Fixing this and other aspects will be easier
with the CI infrastructure in place. For example bindings, static checking
and improved developer ergonomics (e.g., clippy and rustfmt integration),
documentation generation would all be valid starting points.
For developers testing locally with --enable-rust, run "meson subprojects
update --reset" after pulling and before building. Meson does not do this
step automatically due to it being potentially destructive. This should
only affect this initial stabilization period, but a fix is in progress
(I first need to check with the Meson folks whether my script is using
stable interfaces).
Paolo
Junjie Mao (1):
rust: introduce alternative implementation of offset_of!
Manos Pitsidianakis (9):
rust/wrapper.h: define memory_order enum
Revert "rust: add PL011 device model"
rust: add PL011 device model
rust: add definitions for vmstate
rust/pl011: add support for migration
rust/pl011: move CLK_NAME static to function scope
rust/pl011: add TYPE_PL011_LUMINARY device
rust/pl011: remove commented out C code
rust/pl011: Use correct masks for IBRD and FBRD
Paolo Bonzini (30):
qdev: make properties array "const"
meson: import rust module into a global variable
meson: remove repeated search for rust_root_crate.sh
meson: pass rustc_args when building all crates
rust: do not always select X_PL011_RUST
rust: do not use --no-size_t-is-usize
rust: remove uses of #[no_mangle]
rust: modernize link_section usage for ELF platforms
rust: build integration test for the qemu_api crate
rust: cleanup module_init!, use it from #[derive(Object)]
rust: clean up define_property macro
rust: make properties array immutable
rust: provide safe wrapper for MaybeUninit::zeroed()
rust: do not use TYPE_CHARDEV unnecessarily
rust/pl011: fix default value for migrate-clock
rust: patch bilge-impl to allow compilation with 1.63.0
rust: fix cfgs of proc-macro2 for 1.63.0
rust: use std::os::raw instead of core::ffi
rust: introduce a c_str macro
rust: silence unknown warnings for the sake of old compilers
rust: synchronize dependencies between subprojects and Cargo.lock
rust: create a cargo workspace
rust: do not use MaybeUninit::zeroed()
rust: clean up detection of the language
rust: allow version 1.63.0 of rustc
rust: do not use --generate-cstr
rust: allow older version of bindgen
rust: make rustfmt optional
dockerfiles: install bindgen from cargo on Ubuntu 22.04
ci: enable rust in the Debian and Ubuntu system build job
docs/about/build-platforms.rst | 12 +
meson.build | 135 +++++---
include/hw/qdev-core.h | 4 +-
include/hw/qdev-properties.h | 4 +-
rust/wrapper.h | 17 +
hw/core/qdev-properties.c | 26 +-
system/qdev-monitor.c | 2 +-
.gitattributes | 2 +
.gitlab-ci.d/buildtest.yml | 6 +-
meson_options.txt | 2 +
rust/{hw/char/pl011 => }/Cargo.lock | 4 +
rust/Cargo.toml | 7 +
rust/hw/char/Kconfig | 1 -
rust/hw/char/pl011/Cargo.toml | 3 -
rust/hw/char/pl011/src/device.rs | 162 +++++++---
rust/hw/char/pl011/src/device_class.rs | 80 ++++-
rust/hw/char/pl011/src/lib.rs | 6 +-
rust/hw/char/pl011/src/memory_ops.rs | 24 +-
rust/qemu-api-macros/Cargo.lock | 47 ---
rust/qemu-api-macros/Cargo.toml | 5 +-
rust/qemu-api-macros/meson.build | 2 +-
rust/qemu-api-macros/src/lib.rs | 103 ++++--
rust/qemu-api/Cargo.lock | 7 -
rust/qemu-api/Cargo.toml | 10 +-
rust/qemu-api/build.rs | 9 +
rust/qemu-api/meson.build | 44 ++-
rust/qemu-api/src/c_str.rs | 53 +++
rust/qemu-api/src/definitions.rs | 68 ++--
rust/qemu-api/src/device_class.rs | 114 ++-----
rust/qemu-api/src/lib.rs | 23 +-
rust/qemu-api/src/offset_of.rs | 161 +++++++++
rust/qemu-api/src/tests.rs | 49 ---
rust/qemu-api/src/vmstate.rs | 360 +++++++++++++++++++++
rust/qemu-api/src/zeroable.rs | 86 +++++
rust/qemu-api/tests/tests.rs | 79 +++++
scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml | 1 -
scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml | 1 -
scripts/meson-buildoptions.sh | 4 +
subprojects/bilge-impl-0.2-rs.wrap | 1 +
subprojects/packagefiles/bilge-impl-1.63.0.patch | 45 +++
.../packagefiles/proc-macro2-1-rs/meson.build | 4 +-
subprojects/packagefiles/syn-2-rs/meson.build | 1 +
tests/docker/dockerfiles/ubuntu2204.docker | 6 +-
tests/lcitool/mappings.yml | 4 +
tests/lcitool/refresh | 11 +-
45 files changed, 1379 insertions(+), 416 deletions(-)
--
2.47.0
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PULL 01/40] qdev: make properties array "const"
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 02/40] rust/wrapper.h: define memory_order enum Paolo Bonzini
` (39 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Constify all accesses to qdev properties, except for the
ObjectPropertyAccessor itself. This makes it possible to place them in
read-only memory, and also lets Rust bindings switch from "static mut"
arrays to "static"; which is advantageous, because mutable statics are
highly discouraged.
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
include/hw/qdev-core.h | 4 ++--
include/hw/qdev-properties.h | 4 ++--
hw/core/qdev-properties.c | 26 +++++++++++++-------------
system/qdev-monitor.c | 2 +-
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index aa97c34a4be..f9fa291cc63 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -132,7 +132,7 @@ struct DeviceClass {
* ensures a compile-time error if someone attempts to assign
* dc->props directly.
*/
- Property *props_;
+ const Property *props_;
/**
* @user_creatable: Can user instantiate with -device / device_add?
@@ -935,7 +935,7 @@ char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev);
* you attempt to add an existing property defined by a parent class.
* To modify an inherited property you need to use????
*/
-void device_class_set_props(DeviceClass *dc, Property *props);
+void device_class_set_props(DeviceClass *dc, const Property *props);
/**
* device_class_set_parent_realize() - set up for chaining realize fns
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 09aa04ca1e2..26ebd230685 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -37,7 +37,7 @@ struct PropertyInfo {
int (*print)(Object *obj, Property *prop, char *dest, size_t len);
void (*set_default_value)(ObjectProperty *op, const Property *prop);
ObjectProperty *(*create)(ObjectClass *oc, const char *name,
- Property *prop);
+ const Property *prop);
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
ObjectPropertyRelease *release;
@@ -223,7 +223,7 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, Object *obj,
* On error, store error in @errp. Static properties access data in a struct.
* The type of the QOM property is derived from prop->info.
*/
-void qdev_property_add_static(DeviceState *dev, Property *prop);
+void qdev_property_add_static(DeviceState *dev, const Property *prop);
/**
* qdev_alias_all_properties: Create aliases on source for all target properties
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 86a583574dd..315196bd85a 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -749,7 +749,7 @@ const PropertyInfo qdev_prop_array = {
/* --- public helpers --- */
-static Property *qdev_prop_walk(Property *props, const char *name)
+static const Property *qdev_prop_walk(const Property *props, const char *name)
{
if (!props) {
return NULL;
@@ -763,10 +763,10 @@ static Property *qdev_prop_walk(Property *props, const char *name)
return NULL;
}
-static Property *qdev_prop_find(DeviceState *dev, const char *name)
+static const Property *qdev_prop_find(DeviceState *dev, const char *name)
{
ObjectClass *class;
- Property *prop;
+ const Property *prop;
/* device properties */
class = object_get_class(OBJECT(dev));
@@ -840,7 +840,7 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
{
- Property *prop;
+ const Property *prop;
prop = qdev_prop_find(dev, name);
object_property_set_str(OBJECT(dev), name,
@@ -956,7 +956,7 @@ const PropertyInfo qdev_prop_size = {
/* --- object link property --- */
static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
- Property *prop)
+ const Property *prop)
{
return object_class_property_add_link(oc, name, prop->link_type,
prop->offset,
@@ -969,7 +969,7 @@ const PropertyInfo qdev_prop_link = {
.create = create_link_property,
};
-void qdev_property_add_static(DeviceState *dev, Property *prop)
+void qdev_property_add_static(DeviceState *dev, const Property *prop)
{
Object *obj = OBJECT(dev);
ObjectProperty *op;
@@ -980,7 +980,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop)
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
object_property_set_description(obj, prop->name,
prop->info->description);
@@ -994,7 +994,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop)
}
static void qdev_class_add_property(DeviceClass *klass, const char *name,
- Property *prop)
+ const Property *prop)
{
ObjectClass *oc = OBJECT_CLASS(klass);
ObjectProperty *op;
@@ -1007,7 +1007,7 @@ static void qdev_class_add_property(DeviceClass *klass, const char *name,
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
}
if (prop->set_default) {
prop->info->set_default_value(op, prop);
@@ -1046,7 +1046,7 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v,
* Do not use this in new code! QOM Properties added through this interface
* will be given names in the "legacy" namespace.
*/
-static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
+static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
{
g_autofree char *name = NULL;
@@ -1058,12 +1058,12 @@ static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
name = g_strdup_printf("legacy-%s", prop->name);
object_class_property_add(OBJECT_CLASS(dc), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get,
- NULL, NULL, prop);
+ NULL, NULL, (Property *)prop);
}
-void device_class_set_props(DeviceClass *dc, Property *props)
+void device_class_set_props(DeviceClass *dc, const Property *props)
{
- Property *prop;
+ const Property *prop;
dc->props_ = props;
for (prop = props; prop && prop->name; prop++) {
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 44994ea0e16..c346ea6ae4b 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -751,7 +751,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
-static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
+static void qdev_print_props(Monitor *mon, DeviceState *dev, const Property *props,
int indent)
{
if (!props)
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 02/40] rust/wrapper.h: define memory_order enum
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
2024-11-04 17:26 ` [PULL 01/40] qdev: make properties array "const" Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 03/40] Revert "rust: add PL011 device model" Paolo Bonzini
` (38 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Add stub definition of memory_order enum in wrapper.h.
Creating Rust bindings from C code is done by passing the wrapper.h
header to `bindgen`. This fails when library dependencies that use
compiler headers are enabled, and the libclang that bindgen detects does
not match the expected clang version. So far this has only been observed
with the memory_order enum symbols from stdatomic.h. If we add the enum
definition to wrapper.h ourselves, the error does not happen.
Before this commit, if the mismatch happened the following error could
come up:
/usr/include/liburing/barrier.h:72:10: error: use of undeclared identifier 'memory_order_release'
/usr/include/liburing/barrier.h:75:9: error: use of undeclared identifier 'memory_order_acquire'
/usr/include/liburing/barrier.h:75:9: error: use of undeclared identifier 'memory_order_acquire'
/usr/include/liburing/barrier.h:68:9: error: use of undeclared identifier 'memory_order_relaxed'
/usr/include/liburing/barrier.h:65:17: error: use of undeclared identifier 'memory_order_relaxed'
/usr/include/liburing/barrier.h:75:9: error: use of undeclared identifier 'memory_order_acquire'
/usr/include/liburing/barrier.h:75:9: error: use of undeclared identifier 'memory_order_acquire'
/usr/include/liburing/barrier.h:72:10: error: use of undeclared identifier 'memory_order_release'
panicked at [..]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-cli-0.70.1/main.rs:45:36:
Unable to generate bindings
To fix this (on my system) I would have to export CLANG_PATH and
LIBCLANG_PATH:
export CLANG_PATH=/bin/clang-17
export LIBCLANG_PATH=/usr/lib/llvm-17/lib
With these changes applied, bindgen is successful with both the
environment variables set and unset.
Since we're not using those symbols in the bindings (they are only used
by dependencies) this does not affect the generated bindings in any way.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Link: https://lore.kernel.org/r/20241027-rust-wrapper-stdatomic-v2-1-dab27bbf93ea@linaro.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/wrapper.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/rust/wrapper.h b/rust/wrapper.h
index 77e40213efb..285d0eb6ad0 100644
--- a/rust/wrapper.h
+++ b/rust/wrapper.h
@@ -30,6 +30,23 @@
* in order to generate C FFI compatible Rust bindings.
*/
+#ifndef __CLANG_STDATOMIC_H
+#define __CLANG_STDATOMIC_H
+/*
+ * Fix potential missing stdatomic.h error in case bindgen does not insert the
+ * correct libclang header paths on its own. We do not use stdatomic.h symbols
+ * in QEMU code, so it's fine to declare dummy types instead.
+ */
+typedef enum memory_order {
+ memory_order_relaxed,
+ memory_order_consume,
+ memory_order_acquire,
+ memory_order_release,
+ memory_order_acq_rel,
+ memory_order_seq_cst,
+} memory_order;
+#endif /* __CLANG_STDATOMIC_H */
+
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu-io.h"
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 03/40] Revert "rust: add PL011 device model"
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
2024-11-04 17:26 ` [PULL 01/40] qdev: make properties array "const" Paolo Bonzini
2024-11-04 17:26 ` [PULL 02/40] rust/wrapper.h: define memory_order enum Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 04/40] rust: add PL011 device model Paolo Bonzini
` (37 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Patch was applied with invalid authorship by accident, which confuses
git tooling that look at git blame for contributors etc.
Patch will be re-applied with correct authorship right after this
commit.
This reverts commit d0f0cd5b1f7e9780753344548e17ad4df9fcf5d8.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-1-051e7a25b978@linaro.org
---
MAINTAINERS | 5 -
meson.build | 24 -
hw/arm/Kconfig | 30 +-
rust/Kconfig | 1 -
rust/hw/Kconfig | 2 -
rust/hw/char/Kconfig | 3 -
rust/hw/char/meson.build | 1 -
rust/hw/char/pl011/.gitignore | 2 -
rust/hw/char/pl011/Cargo.lock | 134 ----
rust/hw/char/pl011/Cargo.toml | 26 -
rust/hw/char/pl011/README.md | 31 -
rust/hw/char/pl011/meson.build | 26 -
rust/hw/char/pl011/src/device.rs | 599 ------------------
rust/hw/char/pl011/src/device_class.rs | 70 --
rust/hw/char/pl011/src/lib.rs | 586 -----------------
rust/hw/char/pl011/src/memory_ops.rs | 59 --
rust/hw/meson.build | 1 -
rust/meson.build | 2 -
scripts/archive-source.sh | 4 +-
scripts/make-release | 4 +-
scripts/rust/rust_root_crate.sh | 13 -
subprojects/.gitignore | 7 -
subprojects/arbitrary-int-1-rs.wrap | 7 -
subprojects/bilge-0.2-rs.wrap | 7 -
subprojects/bilge-impl-0.2-rs.wrap | 7 -
subprojects/either-1-rs.wrap | 7 -
subprojects/itertools-0.11-rs.wrap | 7 -
.../arbitrary-int-1-rs/meson.build | 19 -
.../packagefiles/bilge-0.2-rs/meson.build | 29 -
.../bilge-impl-0.2-rs/meson.build | 45 --
.../packagefiles/either-1-rs/meson.build | 24 -
.../itertools-0.11-rs/meson.build | 30 -
.../proc-macro-error-1-rs/meson.build | 40 --
.../proc-macro-error-attr-1-rs/meson.build | 32 -
.../unicode-ident-1-rs/meson.build | 20 -
subprojects/proc-macro-error-1-rs.wrap | 7 -
subprojects/proc-macro-error-attr-1-rs.wrap | 7 -
37 files changed, 12 insertions(+), 1906 deletions(-)
delete mode 100644 rust/hw/Kconfig
delete mode 100644 rust/hw/char/Kconfig
delete mode 100644 rust/hw/char/meson.build
delete mode 100644 rust/hw/char/pl011/.gitignore
delete mode 100644 rust/hw/char/pl011/Cargo.lock
delete mode 100644 rust/hw/char/pl011/Cargo.toml
delete mode 100644 rust/hw/char/pl011/README.md
delete mode 100644 rust/hw/char/pl011/meson.build
delete mode 100644 rust/hw/char/pl011/src/device.rs
delete mode 100644 rust/hw/char/pl011/src/device_class.rs
delete mode 100644 rust/hw/char/pl011/src/lib.rs
delete mode 100644 rust/hw/char/pl011/src/memory_ops.rs
delete mode 100644 rust/hw/meson.build
delete mode 100755 scripts/rust/rust_root_crate.sh
delete mode 100644 subprojects/arbitrary-int-1-rs.wrap
delete mode 100644 subprojects/bilge-0.2-rs.wrap
delete mode 100644 subprojects/bilge-impl-0.2-rs.wrap
delete mode 100644 subprojects/either-1-rs.wrap
delete mode 100644 subprojects/itertools-0.11-rs.wrap
delete mode 100644 subprojects/packagefiles/arbitrary-int-1-rs/meson.build
delete mode 100644 subprojects/packagefiles/bilge-0.2-rs/meson.build
delete mode 100644 subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
delete mode 100644 subprojects/packagefiles/either-1-rs/meson.build
delete mode 100644 subprojects/packagefiles/itertools-0.11-rs/meson.build
delete mode 100644 subprojects/packagefiles/proc-macro-error-1-rs/meson.build
delete mode 100644 subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
delete mode 100644 subprojects/packagefiles/unicode-ident-1-rs/meson.build
delete mode 100644 subprojects/proc-macro-error-1-rs.wrap
delete mode 100644 subprojects/proc-macro-error-attr-1-rs.wrap
diff --git a/MAINTAINERS b/MAINTAINERS
index f48d9142b8a..3f17295d41e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1138,11 +1138,6 @@ F: include/hw/*/microbit*.h
F: tests/qtest/microbit-test.c
F: docs/system/arm/nrf.rst
-ARM PL011 Rust device
-M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-S: Maintained
-F: rust/hw/char/pl011/
-
AVR Machines
-------------
diff --git a/meson.build b/meson.build
index f7d45175212..f290bb70b1d 100644
--- a/meson.build
+++ b/meson.build
@@ -3534,7 +3534,6 @@ qom_ss = ss.source_set()
system_ss = ss.source_set()
specific_fuzz_ss = ss.source_set()
specific_ss = ss.source_set()
-rust_devices_ss = ss.source_set()
stub_ss = ss.source_set()
trace_ss = ss.source_set()
user_ss = ss.source_set()
@@ -4082,29 +4081,6 @@ foreach target : target_dirs
arch_srcs += target_specific.sources()
arch_deps += target_specific.dependencies()
- if have_rust and have_system
- target_rust = rust_devices_ss.apply(config_target, strict: false)
- crates = []
- foreach dep : target_rust.dependencies()
- crates += dep.get_variable('crate')
- endforeach
- if crates.length() > 0
- rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
- output: 'rust_' + target.underscorify() + '.rs',
- command: [find_program('scripts/rust/rust_root_crate.sh')] + crates,
- capture: true,
- build_by_default: true,
- build_always_stale: true)
- rlib = static_library('rust_' + target.underscorify(),
- rlib_rs,
- dependencies: target_rust.dependencies(),
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_args: rustc_args,
- rust_abi: 'c')
- arch_deps += declare_dependency(link_whole: [rlib])
- endif
- endif
-
# allow using headers from the dependencies but do not include the sources,
# because this emulator only needs those in "objects". For external
# dependencies, the full dependency is included below in the executable.
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index e7fd9338d11..53eb7bb3d01 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -20,8 +20,7 @@ config ARM_VIRT
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL061 # GPIO
select GPIO_PWR
@@ -74,8 +73,7 @@ config HIGHBANK
select AHCI
select ARM_TIMER # sp804
select ARM_V7M
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL022 # SPI
select PL031 # RTC
select PL061 # GPIO
@@ -88,8 +86,7 @@ config INTEGRATOR
depends on TCG && ARM
select ARM_TIMER
select INTEGRATOR_DEBUG
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL041 # audio
select PL050 # keyboard/mouse
@@ -107,8 +104,7 @@ config MUSCA
default y
depends on TCG && ARM
select ARMSSE
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011
select PL031
select SPLIT_IRQ
select UNIMP
@@ -172,8 +168,7 @@ config REALVIEW
select WM8750 # audio codec
select LSI_SCSI_PCI
select PCI
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL041 # audio codec
select PL050 # keyboard/mouse
@@ -198,8 +193,7 @@ config SBSA_REF
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL061 # GPIO
select USB_XHCI_SYSBUS
@@ -223,8 +217,7 @@ config STELLARIS
select ARM_V7M
select CMSDK_APB_WATCHDOG
select I2C
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL022 # SPI
select PL061 # GPIO
select SSD0303 # OLED display
@@ -284,8 +277,7 @@ config VEXPRESS
select ARM_TIMER # sp804
select LAN9118
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL041 # audio codec
select PL181 # display
select REALVIEW
@@ -370,8 +362,7 @@ config RASPI
default y
depends on TCG && ARM
select FRAMEBUFFER
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select SDHCI
select USB_DWC2
select BCM2835_SPI
@@ -447,8 +438,7 @@ config XLNX_VERSAL
select ARM_GIC
select CPU_CLUSTER
select DEVICE_TREE
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011
select CADENCE
select VIRTIO_MMIO
select UNIMP
diff --git a/rust/Kconfig b/rust/Kconfig
index f9f5c390988..e69de29bb2d 100644
--- a/rust/Kconfig
+++ b/rust/Kconfig
@@ -1 +0,0 @@
-source hw/Kconfig
diff --git a/rust/hw/Kconfig b/rust/hw/Kconfig
deleted file mode 100644
index 4d934f30afe..00000000000
--- a/rust/hw/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-# devices Kconfig
-source char/Kconfig
diff --git a/rust/hw/char/Kconfig b/rust/hw/char/Kconfig
deleted file mode 100644
index a1732a9e97f..00000000000
--- a/rust/hw/char/Kconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-config X_PL011_RUST
- bool
- default y if HAVE_RUST
diff --git a/rust/hw/char/meson.build b/rust/hw/char/meson.build
deleted file mode 100644
index 5716dc43ef6..00000000000
--- a/rust/hw/char/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-subdir('pl011')
diff --git a/rust/hw/char/pl011/.gitignore b/rust/hw/char/pl011/.gitignore
deleted file mode 100644
index 71eaff2035d..00000000000
--- a/rust/hw/char/pl011/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Ignore generated bindings file overrides.
-src/bindings.rs.inc
diff --git a/rust/hw/char/pl011/Cargo.lock b/rust/hw/char/pl011/Cargo.lock
deleted file mode 100644
index b58cebb186e..00000000000
--- a/rust/hw/char/pl011/Cargo.lock
+++ /dev/null
@@ -1,134 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "arbitrary-int"
-version = "1.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
-
-[[package]]
-name = "bilge"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57"
-dependencies = [
- "arbitrary-int",
- "bilge-impl",
-]
-
-[[package]]
-name = "bilge-impl"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8"
-dependencies = [
- "itertools",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "either"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
-
-[[package]]
-name = "itertools"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "pl011"
-version = "0.1.0"
-dependencies = [
- "bilge",
- "bilge-impl",
- "qemu_api",
- "qemu_api_macros",
-]
-
-[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.84"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "qemu_api"
-version = "0.1.0"
-
-[[package]]
-name = "qemu_api_macros"
-version = "0.1.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.66"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml
deleted file mode 100644
index b089e3dded6..00000000000
--- a/rust/hw/char/pl011/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "pl011"
-version = "0.1.0"
-edition = "2021"
-authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
-license = "GPL-2.0-or-later"
-readme = "README.md"
-homepage = "https://www.qemu.org"
-description = "pl011 device model for QEMU"
-repository = "https://gitlab.com/epilys/rust-for-qemu"
-resolver = "2"
-publish = false
-keywords = []
-categories = []
-
-[lib]
-crate-type = ["staticlib"]
-
-[dependencies]
-bilge = { version = "0.2.0" }
-bilge-impl = { version = "0.2.0" }
-qemu_api = { path = "../../../qemu-api" }
-qemu_api_macros = { path = "../../../qemu-api-macros" }
-
-# Do not include in any global workspace
-[workspace]
diff --git a/rust/hw/char/pl011/README.md b/rust/hw/char/pl011/README.md
deleted file mode 100644
index cd7dea31634..00000000000
--- a/rust/hw/char/pl011/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# PL011 QEMU Device Model
-
-This library implements a device model for the PrimeCell® UART (PL011)
-device in QEMU.
-
-## Build static lib
-
-Host build target must be explicitly specified:
-
-```sh
-cargo build --target x86_64-unknown-linux-gnu
-```
-
-Replace host target triplet if necessary.
-
-## Generate Rust documentation
-
-To generate docs for this crate, including private items:
-
-```sh
-cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
-```
-
-To include direct dependencies like `bilge` (bitmaps for register types):
-
-```sh
-cargo tree --depth 1 -e normal --prefix none \
- | cut -d' ' -f1 \
- | xargs printf -- '-p %s\n' \
- | xargs cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
-```
diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build
deleted file mode 100644
index 547cca5a96f..00000000000
--- a/rust/hw/char/pl011/meson.build
+++ /dev/null
@@ -1,26 +0,0 @@
-subproject('bilge-0.2-rs', required: true)
-subproject('bilge-impl-0.2-rs', required: true)
-
-bilge_dep = dependency('bilge-0.2-rs')
-bilge_impl_dep = dependency('bilge-impl-0.2-rs')
-
-_libpl011_rs = static_library(
- 'pl011',
- files('src/lib.rs'),
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_abi: 'rust',
- dependencies: [
- bilge_dep,
- bilge_impl_dep,
- qemu_api,
- qemu_api_macros,
- ],
-)
-
-rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
- link_whole: [_libpl011_rs],
- # Putting proc macro crates in `dependencies` is necessary for Meson to find
- # them when compiling the root per-target static rust lib.
- dependencies: [bilge_impl_dep, qemu_api_macros],
- variables: {'crate': 'pl011'},
-)])
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
deleted file mode 100644
index c7193b41bee..00000000000
--- a/rust/hw/char/pl011/src/device.rs
+++ /dev/null
@@ -1,599 +0,0 @@
-// Copyright 2024, Linaro Limited
-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-use core::{
- ffi::{c_int, c_uchar, c_uint, c_void, CStr},
- ptr::{addr_of, addr_of_mut, NonNull},
-};
-
-use qemu_api::{
- bindings::{self, *},
- definitions::ObjectImpl,
-};
-
-use crate::{
- memory_ops::PL011_OPS,
- registers::{self, Interrupt},
- RegisterOffset,
-};
-
-static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
-
-const DATA_BREAK: u32 = 1 << 10;
-
-/// QEMU sourced constant.
-pub const PL011_FIFO_DEPTH: usize = 16_usize;
-
-#[repr(C)]
-#[derive(Debug, qemu_api_macros::Object)]
-/// PL011 Device Model in QEMU
-pub struct PL011State {
- pub parent_obj: SysBusDevice,
- pub iomem: MemoryRegion,
- #[doc(alias = "fr")]
- pub flags: registers::Flags,
- #[doc(alias = "lcr")]
- pub line_control: registers::LineControl,
- #[doc(alias = "rsr")]
- pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
- #[doc(alias = "cr")]
- pub control: registers::Control,
- pub dmacr: u32,
- pub int_enabled: u32,
- pub int_level: u32,
- pub read_fifo: [u32; PL011_FIFO_DEPTH],
- pub ilpr: u32,
- pub ibrd: u32,
- pub fbrd: u32,
- pub ifl: u32,
- pub read_pos: usize,
- pub read_count: usize,
- pub read_trigger: usize,
- #[doc(alias = "chr")]
- pub char_backend: CharBackend,
- /// QEMU interrupts
- ///
- /// ```text
- /// * sysbus MMIO region 0: device registers
- /// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
- /// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
- /// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
- /// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
- /// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
- /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
- /// ```
- #[doc(alias = "irq")]
- pub interrupts: [qemu_irq; 6usize],
- #[doc(alias = "clk")]
- pub clock: NonNull<Clock>,
- #[doc(alias = "migrate_clk")]
- pub migrate_clock: bool,
-}
-
-impl ObjectImpl for PL011State {
- type Class = PL011Class;
- const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
- const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
- const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_SYS_BUS_DEVICE);
- const ABSTRACT: bool = false;
- const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = Some(pl011_init);
- const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
- const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
-}
-
-#[repr(C)]
-pub struct PL011Class {
- _inner: [u8; 0],
-}
-
-impl qemu_api::definitions::Class for PL011Class {
- const CLASS_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
- > = Some(crate::device_class::pl011_class_init);
- const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
- > = None;
-}
-
-#[used]
-pub static CLK_NAME: &CStr = c"clk";
-
-impl PL011State {
- /// Initializes a pre-allocated, unitialized instance of `PL011State`.
- ///
- /// # Safety
- ///
- /// `self` must point to a correctly sized and aligned location for the
- /// `PL011State` type. It must not be called more than once on the same
- /// location/instance. All its fields are expected to hold unitialized
- /// values with the sole exception of `parent_obj`.
- pub unsafe fn init(&mut self) {
- let dev = addr_of_mut!(*self).cast::<DeviceState>();
- // SAFETY:
- //
- // self and self.iomem are guaranteed to be valid at this point since callers
- // must make sure the `self` reference is valid.
- unsafe {
- memory_region_init_io(
- addr_of_mut!(self.iomem),
- addr_of_mut!(*self).cast::<Object>(),
- &PL011_OPS,
- addr_of_mut!(*self).cast::<c_void>(),
- Self::TYPE_INFO.name,
- 0x1000,
- );
- let sbd = addr_of_mut!(*self).cast::<SysBusDevice>();
- sysbus_init_mmio(sbd, addr_of_mut!(self.iomem));
- for irq in self.interrupts.iter_mut() {
- sysbus_init_irq(sbd, irq);
- }
- }
- // SAFETY:
- //
- // self.clock is not initialized at this point; but since `NonNull<_>` is Copy,
- // we can overwrite the undefined value without side effects. This is
- // safe since all PL011State instances are created by QOM code which
- // calls this function to initialize the fields; therefore no code is
- // able to access an invalid self.clock value.
- unsafe {
- self.clock = NonNull::new(qdev_init_clock_in(
- dev,
- CLK_NAME.as_ptr(),
- None, /* pl011_clock_update */
- addr_of_mut!(*self).cast::<c_void>(),
- ClockEvent::ClockUpdate.0,
- ))
- .unwrap();
- }
- }
-
- pub fn read(
- &mut self,
- offset: hwaddr,
- _size: core::ffi::c_uint,
- ) -> std::ops::ControlFlow<u64, u64> {
- use RegisterOffset::*;
-
- std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
- Err(v) if (0x3f8..0x400).contains(&v) => {
- u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize])
- }
- Err(_) => {
- // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
- 0
- }
- Ok(DR) => {
- // s->flags &= ~PL011_FLAG_RXFF;
- self.flags.set_receive_fifo_full(false);
- let c = self.read_fifo[self.read_pos];
- if self.read_count > 0 {
- self.read_count -= 1;
- self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
- }
- if self.read_count == 0 {
- // self.flags |= PL011_FLAG_RXFE;
- self.flags.set_receive_fifo_empty(true);
- }
- if self.read_count + 1 == self.read_trigger {
- //self.int_level &= ~ INT_RX;
- self.int_level &= !registers::INT_RX;
- }
- // Update error bits.
- self.receive_status_error_clear = c.to_be_bytes()[3].into();
- self.update();
- // Must call qemu_chr_fe_accept_input, so return Continue:
- return std::ops::ControlFlow::Continue(c.into());
- }
- Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
- Ok(FR) => u16::from(self.flags).into(),
- Ok(FBRD) => self.fbrd.into(),
- Ok(ILPR) => self.ilpr.into(),
- Ok(IBRD) => self.ibrd.into(),
- Ok(LCR_H) => u16::from(self.line_control).into(),
- Ok(CR) => {
- // We exercise our self-control.
- u16::from(self.control).into()
- }
- Ok(FLS) => self.ifl.into(),
- Ok(IMSC) => self.int_enabled.into(),
- Ok(RIS) => self.int_level.into(),
- Ok(MIS) => u64::from(self.int_level & self.int_enabled),
- Ok(ICR) => {
- // "The UARTICR Register is the interrupt clear register and is write-only"
- // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
- 0
- }
- Ok(DMACR) => self.dmacr.into(),
- })
- }
-
- pub fn write(&mut self, offset: hwaddr, value: u64) {
- // eprintln!("write offset {offset} value {value}");
- use RegisterOffset::*;
- let value: u32 = value as u32;
- match RegisterOffset::try_from(offset) {
- Err(_bad_offset) => {
- eprintln!("write bad offset {offset} value {value}");
- }
- Ok(DR) => {
- // ??? Check if transmitter is enabled.
- let ch: u8 = value as u8;
- // XXX this blocks entire thread. Rewrite to use
- // qemu_chr_fe_write and background I/O callbacks
-
- // SAFETY: self.char_backend is a valid CharBackend instance after it's been
- // initialized in realize().
- unsafe {
- qemu_chr_fe_write_all(addr_of_mut!(self.char_backend), &ch, 1);
- }
- self.loopback_tx(value);
- self.int_level |= registers::INT_TX;
- self.update();
- }
- Ok(RSR) => {
- self.receive_status_error_clear = 0.into();
- }
- Ok(FR) => {
- // flag writes are ignored
- }
- Ok(ILPR) => {
- self.ilpr = value;
- }
- Ok(IBRD) => {
- self.ibrd = value;
- }
- Ok(FBRD) => {
- self.fbrd = value;
- }
- Ok(LCR_H) => {
- let value = value as u16;
- let new_val: registers::LineControl = value.into();
- // Reset the FIFO state on FIFO enable or disable
- if bool::from(self.line_control.fifos_enabled())
- ^ bool::from(new_val.fifos_enabled())
- {
- self.reset_fifo();
- }
- if self.line_control.send_break() ^ new_val.send_break() {
- let mut break_enable: c_int = new_val.send_break().into();
- // SAFETY: self.char_backend is a valid CharBackend instance after it's been
- // initialized in realize().
- unsafe {
- qemu_chr_fe_ioctl(
- addr_of_mut!(self.char_backend),
- CHR_IOCTL_SERIAL_SET_BREAK as i32,
- addr_of_mut!(break_enable).cast::<c_void>(),
- );
- }
- self.loopback_break(break_enable > 0);
- }
- self.line_control = new_val;
- self.set_read_trigger();
- }
- Ok(CR) => {
- // ??? Need to implement the enable bit.
- let value = value as u16;
- self.control = value.into();
- self.loopback_mdmctrl();
- }
- Ok(FLS) => {
- self.ifl = value;
- self.set_read_trigger();
- }
- Ok(IMSC) => {
- self.int_enabled = value;
- self.update();
- }
- Ok(RIS) => {}
- Ok(MIS) => {}
- Ok(ICR) => {
- self.int_level &= !value;
- self.update();
- }
- Ok(DMACR) => {
- self.dmacr = value;
- if value & 3 > 0 {
- // qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
- eprintln!("pl011: DMA not implemented");
- }
- }
- }
- }
-
- #[inline]
- fn loopback_tx(&mut self, value: u32) {
- if !self.loopback_enabled() {
- return;
- }
-
- // Caveat:
- //
- // In real hardware, TX loopback happens at the serial-bit level
- // and then reassembled by the RX logics back into bytes and placed
- // into the RX fifo. That is, loopback happens after TX fifo.
- //
- // Because the real hardware TX fifo is time-drained at the frame
- // rate governed by the configured serial format, some loopback
- // bytes in TX fifo may still be able to get into the RX fifo
- // that could be full at times while being drained at software
- // pace.
- //
- // In such scenario, the RX draining pace is the major factor
- // deciding which loopback bytes get into the RX fifo, unless
- // hardware flow-control is enabled.
- //
- // For simplicity, the above described is not emulated.
- self.put_fifo(value);
- }
-
- fn loopback_mdmctrl(&mut self) {
- if !self.loopback_enabled() {
- return;
- }
-
- /*
- * Loopback software-driven modem control outputs to modem status inputs:
- * FR.RI <= CR.Out2
- * FR.DCD <= CR.Out1
- * FR.CTS <= CR.RTS
- * FR.DSR <= CR.DTR
- *
- * The loopback happens immediately even if this call is triggered
- * by setting only CR.LBE.
- *
- * CTS/RTS updates due to enabled hardware flow controls are not
- * dealt with here.
- */
-
- //fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
- // PL011_FLAG_DSR | PL011_FLAG_CTS);
- //fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
- //fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
- //fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
- //fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
- //
- self.flags.set_ring_indicator(self.control.out_2());
- self.flags.set_data_carrier_detect(self.control.out_1());
- self.flags.set_clear_to_send(self.control.request_to_send());
- self.flags
- .set_data_set_ready(self.control.data_transmit_ready());
-
- // Change interrupts based on updated FR
- let mut il = self.int_level;
-
- il &= !Interrupt::MS;
- //il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
- //il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
- //il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
- //il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
-
- if self.flags.data_set_ready() {
- il |= Interrupt::DSR as u32;
- }
- if self.flags.data_carrier_detect() {
- il |= Interrupt::DCD as u32;
- }
- if self.flags.clear_to_send() {
- il |= Interrupt::CTS as u32;
- }
- if self.flags.ring_indicator() {
- il |= Interrupt::RI as u32;
- }
- self.int_level = il;
- self.update();
- }
-
- fn loopback_break(&mut self, enable: bool) {
- if enable {
- self.loopback_tx(DATA_BREAK);
- }
- }
-
- fn set_read_trigger(&mut self) {
- self.read_trigger = 1;
- }
-
- pub fn realize(&mut self) {
- // SAFETY: self.char_backend has the correct size and alignment for a
- // CharBackend object, and its callbacks are of the correct types.
- unsafe {
- qemu_chr_fe_set_handlers(
- addr_of_mut!(self.char_backend),
- Some(pl011_can_receive),
- Some(pl011_receive),
- Some(pl011_event),
- None,
- addr_of_mut!(*self).cast::<c_void>(),
- core::ptr::null_mut(),
- true,
- );
- }
- }
-
- pub fn reset(&mut self) {
- self.line_control.reset();
- self.receive_status_error_clear.reset();
- self.dmacr = 0;
- self.int_enabled = 0;
- self.int_level = 0;
- self.ilpr = 0;
- self.ibrd = 0;
- self.fbrd = 0;
- self.read_trigger = 1;
- self.ifl = 0x12;
- self.control.reset();
- self.flags = 0.into();
- self.reset_fifo();
- }
-
- pub fn reset_fifo(&mut self) {
- self.read_count = 0;
- self.read_pos = 0;
-
- /* Reset FIFO flags */
- self.flags.reset();
- }
-
- pub fn can_receive(&self) -> bool {
- // trace_pl011_can_receive(s->lcr, s->read_count, r);
- self.read_count < self.fifo_depth()
- }
-
- pub fn event(&mut self, event: QEMUChrEvent) {
- if event == bindings::QEMUChrEvent::CHR_EVENT_BREAK && !self.fifo_enabled() {
- self.put_fifo(DATA_BREAK);
- self.receive_status_error_clear.set_break_error(true);
- }
- }
-
- #[inline]
- pub fn fifo_enabled(&self) -> bool {
- matches!(self.line_control.fifos_enabled(), registers::Mode::FIFO)
- }
-
- #[inline]
- pub fn loopback_enabled(&self) -> bool {
- self.control.enable_loopback()
- }
-
- #[inline]
- pub fn fifo_depth(&self) -> usize {
- // Note: FIFO depth is expected to be power-of-2
- if self.fifo_enabled() {
- return PL011_FIFO_DEPTH;
- }
- 1
- }
-
- pub fn put_fifo(&mut self, value: c_uint) {
- let depth = self.fifo_depth();
- assert!(depth > 0);
- let slot = (self.read_pos + self.read_count) & (depth - 1);
- self.read_fifo[slot] = value;
- self.read_count += 1;
- // s->flags &= ~PL011_FLAG_RXFE;
- self.flags.set_receive_fifo_empty(false);
- if self.read_count == depth {
- //s->flags |= PL011_FLAG_RXFF;
- self.flags.set_receive_fifo_full(true);
- }
-
- if self.read_count == self.read_trigger {
- self.int_level |= registers::INT_RX;
- self.update();
- }
- }
-
- pub fn update(&self) {
- let flags = self.int_level & self.int_enabled;
- for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
- // SAFETY: self.interrupts have been initialized in init().
- unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
- }
- }
-}
-
-/// Which bits in the interrupt status matter for each outbound IRQ line ?
-pub const IRQMASK: [u32; 6] = [
- /* combined IRQ */
- Interrupt::E
- | Interrupt::MS
- | Interrupt::RT as u32
- | Interrupt::TX as u32
- | Interrupt::RX as u32,
- Interrupt::RX as u32,
- Interrupt::TX as u32,
- Interrupt::RT as u32,
- Interrupt::MS,
- Interrupt::E,
-];
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
- unsafe {
- debug_assert!(!opaque.is_null());
- let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
- state.as_ref().can_receive().into()
- }
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-///
-/// The buffer and size arguments must also be valid.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_receive(
- opaque: *mut core::ffi::c_void,
- buf: *const u8,
- size: core::ffi::c_int,
-) {
- unsafe {
- debug_assert!(!opaque.is_null());
- let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
- if state.as_ref().loopback_enabled() {
- return;
- }
- if size > 0 {
- debug_assert!(!buf.is_null());
- state.as_mut().put_fifo(c_uint::from(buf.read_volatile()))
- }
- }
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
- unsafe {
- debug_assert!(!opaque.is_null());
- let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
- state.as_mut().event(event)
- }
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer for `chr`.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_create(
- addr: u64,
- irq: qemu_irq,
- chr: *mut Chardev,
-) -> *mut DeviceState {
- unsafe {
- let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
- let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
-
- qdev_prop_set_chr(dev, bindings::TYPE_CHARDEV.as_ptr(), chr);
- sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
- sysbus_mmio_map(sysbus, 0, addr);
- sysbus_connect_irq(sysbus, 0, irq);
- dev
- }
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_init(obj: *mut Object) {
- unsafe {
- debug_assert!(!obj.is_null());
- let mut state = NonNull::new_unchecked(obj.cast::<PL011State>());
- state.as_mut().init();
- }
-}
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
deleted file mode 100644
index b7ab31af02d..00000000000
--- a/rust/hw/char/pl011/src/device_class.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2024, Linaro Limited
-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-use core::ptr::NonNull;
-
-use qemu_api::{bindings::*, definitions::ObjectImpl};
-
-use crate::device::PL011State;
-
-#[used]
-pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
- name: PL011State::TYPE_INFO.name,
- unmigratable: true,
- ..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() }
-};
-
-qemu_api::declare_properties! {
- PL011_PROPERTIES,
- qemu_api::define_property!(
- c"chardev",
- PL011State,
- char_backend,
- unsafe { &qdev_prop_chr },
- CharBackend
- ),
- qemu_api::define_property!(
- c"migrate-clk",
- PL011State,
- migrate_clock,
- unsafe { &qdev_prop_bool },
- bool
- ),
-}
-
-qemu_api::device_class_init! {
- pl011_class_init,
- props => PL011_PROPERTIES,
- realize_fn => Some(pl011_realize),
- legacy_reset_fn => Some(pl011_reset),
- vmsd => VMSTATE_PL011,
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
- unsafe {
- assert!(!dev.is_null());
- let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
- state.as_mut().realize();
- }
-}
-
-/// # Safety
-///
-/// We expect the FFI user of this function to pass a valid pointer, that has
-/// the same size as [`PL011State`]. We also expect the device is
-/// readable/writeable from one thread at any time.
-#[no_mangle]
-pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
- unsafe {
- assert!(!dev.is_null());
- let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
- state.as_mut().reset();
- }
-}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
deleted file mode 100644
index 2939ee50c99..00000000000
--- a/rust/hw/char/pl011/src/lib.rs
+++ /dev/null
@@ -1,586 +0,0 @@
-// Copyright 2024, Linaro Limited
-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-// SPDX-License-Identifier: GPL-2.0-or-later
-//
-// PL011 QEMU Device Model
-//
-// This library implements a device model for the PrimeCell® UART (PL011)
-// device in QEMU.
-//
-#![doc = include_str!("../README.md")]
-//! # Library crate
-//!
-//! See [`PL011State`](crate::device::PL011State) for the device model type and
-//! the [`registers`] module for register types.
-
-#![deny(
- rustdoc::broken_intra_doc_links,
- rustdoc::redundant_explicit_links,
- clippy::correctness,
- clippy::suspicious,
- clippy::complexity,
- clippy::perf,
- clippy::cargo,
- clippy::nursery,
- clippy::style,
- // restriction group
- clippy::dbg_macro,
- clippy::as_underscore,
- clippy::assertions_on_result_states,
- // pedantic group
- clippy::doc_markdown,
- clippy::borrow_as_ptr,
- clippy::cast_lossless,
- clippy::option_if_let_else,
- clippy::missing_const_for_fn,
- clippy::cognitive_complexity,
- clippy::missing_safety_doc,
- )]
-
-extern crate bilge;
-extern crate bilge_impl;
-extern crate qemu_api;
-
-pub mod device;
-pub mod device_class;
-pub mod memory_ops;
-
-pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
-
-/// Offset of each register from the base memory address of the device.
-///
-/// # Source
-/// ARM DDI 0183G, Table 3-1 p.3-3
-#[doc(alias = "offset")]
-#[allow(non_camel_case_types)]
-#[repr(u64)]
-#[derive(Debug)]
-pub enum RegisterOffset {
- /// Data Register
- ///
- /// A write to this register initiates the actual data transmission
- #[doc(alias = "UARTDR")]
- DR = 0x000,
- /// Receive Status Register or Error Clear Register
- #[doc(alias = "UARTRSR")]
- #[doc(alias = "UARTECR")]
- RSR = 0x004,
- /// Flag Register
- ///
- /// A read of this register shows if transmission is complete
- #[doc(alias = "UARTFR")]
- FR = 0x018,
- /// Fractional Baud Rate Register
- ///
- /// responsible for baud rate speed
- #[doc(alias = "UARTFBRD")]
- FBRD = 0x028,
- /// `IrDA` Low-Power Counter Register
- #[doc(alias = "UARTILPR")]
- ILPR = 0x020,
- /// Integer Baud Rate Register
- ///
- /// Responsible for baud rate speed
- #[doc(alias = "UARTIBRD")]
- IBRD = 0x024,
- /// line control register (data frame format)
- #[doc(alias = "UARTLCR_H")]
- LCR_H = 0x02C,
- /// Toggle UART, transmission or reception
- #[doc(alias = "UARTCR")]
- CR = 0x030,
- /// Interrupt FIFO Level Select Register
- #[doc(alias = "UARTIFLS")]
- FLS = 0x034,
- /// Interrupt Mask Set/Clear Register
- #[doc(alias = "UARTIMSC")]
- IMSC = 0x038,
- /// Raw Interrupt Status Register
- #[doc(alias = "UARTRIS")]
- RIS = 0x03C,
- /// Masked Interrupt Status Register
- #[doc(alias = "UARTMIS")]
- MIS = 0x040,
- /// Interrupt Clear Register
- #[doc(alias = "UARTICR")]
- ICR = 0x044,
- /// DMA control Register
- #[doc(alias = "UARTDMACR")]
- DMACR = 0x048,
- ///// Reserved, offsets `0x04C` to `0x07C`.
- //Reserved = 0x04C,
-}
-
-impl core::convert::TryFrom<u64> for RegisterOffset {
- type Error = u64;
-
- fn try_from(value: u64) -> Result<Self, Self::Error> {
- macro_rules! case {
- ($($discriminant:ident),*$(,)*) => {
- /* check that matching on all macro arguments compiles, which means we are not
- * missing any enum value; if the type definition ever changes this will stop
- * compiling.
- */
- const fn _assert_exhaustive(val: RegisterOffset) {
- match val {
- $(RegisterOffset::$discriminant => (),)*
- }
- }
-
- match value {
- $(x if x == Self::$discriminant as u64 => Ok(Self::$discriminant),)*
- _ => Err(value),
- }
- }
- }
- case! { DR, RSR, FR, FBRD, ILPR, IBRD, LCR_H, CR, FLS, IMSC, RIS, MIS, ICR, DMACR }
- }
-}
-
-pub mod registers {
- //! Device registers exposed as typed structs which are backed by arbitrary
- //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
- //!
- //! All PL011 registers are essentially 32-bit wide, but are typed here as
- //! bitmaps with only the necessary width. That is, if a struct bitmap
- //! in this module is for example 16 bits long, it should be conceived
- //! as a 32-bit register where the unmentioned higher bits are always
- //! unused thus treated as zero when read or written.
- use bilge::prelude::*;
-
- // TODO: FIFO Mode has different semantics
- /// Data Register, `UARTDR`
- ///
- /// The `UARTDR` register is the data register.
- ///
- /// For words to be transmitted:
- ///
- /// - if the FIFOs are enabled, data written to this location is pushed onto
- /// the transmit
- /// FIFO
- /// - if the FIFOs are not enabled, data is stored in the transmitter
- /// holding register (the
- /// bottom word of the transmit FIFO).
- ///
- /// The write operation initiates transmission from the UART. The data is
- /// prefixed with a start bit, appended with the appropriate parity bit
- /// (if parity is enabled), and a stop bit. The resultant word is then
- /// transmitted.
- ///
- /// For received words:
- ///
- /// - if the FIFOs are enabled, the data byte and the 4-bit status (break,
- /// frame, parity,
- /// and overrun) is pushed onto the 12-bit wide receive FIFO
- /// - if the FIFOs are not enabled, the data byte and status are stored in
- /// the receiving
- /// holding register (the bottom word of the receive FIFO).
- ///
- /// The received data byte is read by performing reads from the `UARTDR`
- /// register along with the corresponding status information. The status
- /// information can also be read by a read of the `UARTRSR/UARTECR`
- /// register.
- ///
- /// # Note
- ///
- /// You must disable the UART before any of the control registers are
- /// reprogrammed. When the UART is disabled in the middle of
- /// transmission or reception, it completes the current character before
- /// stopping.
- ///
- /// # Source
- /// ARM DDI 0183G 3.3.1 Data Register, UARTDR
- #[bitsize(16)]
- #[derive(Clone, Copy, DebugBits, FromBits)]
- #[doc(alias = "UARTDR")]
- pub struct Data {
- _reserved: u4,
- pub data: u8,
- pub framing_error: bool,
- pub parity_error: bool,
- pub break_error: bool,
- pub overrun_error: bool,
- }
-
- // TODO: FIFO Mode has different semantics
- /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR`
- ///
- /// The UARTRSR/UARTECR register is the receive status register/error clear
- /// register. Receive status can also be read from the `UARTRSR`
- /// register. If the status is read from this register, then the status
- /// information for break, framing and parity corresponds to the
- /// data character read from the [Data register](Data), `UARTDR` prior to
- /// reading the UARTRSR register. The status information for overrun is
- /// set immediately when an overrun condition occurs.
- ///
- ///
- /// # Note
- /// The received data character must be read first from the [Data
- /// Register](Data), `UARTDR` before reading the error status associated
- /// with that data character from the `UARTRSR` register. This read
- /// sequence cannot be reversed, because the `UARTRSR` register is
- /// updated only when a read occurs from the `UARTDR` register. However,
- /// the status information can also be obtained by reading the `UARTDR`
- /// register
- ///
- /// # Source
- /// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
- /// UARTRSR/UARTECR
- #[bitsize(8)]
- #[derive(Clone, Copy, DebugBits, FromBits)]
- pub struct ReceiveStatusErrorClear {
- pub framing_error: bool,
- pub parity_error: bool,
- pub break_error: bool,
- pub overrun_error: bool,
- _reserved_unpredictable: u4,
- }
-
- impl ReceiveStatusErrorClear {
- pub fn reset(&mut self) {
- // All the bits are cleared to 0 on reset.
- *self = 0.into();
- }
- }
-
- impl Default for ReceiveStatusErrorClear {
- fn default() -> Self {
- 0.into()
- }
- }
-
- #[bitsize(16)]
- #[derive(Clone, Copy, DebugBits, FromBits)]
- /// Flag Register, `UARTFR`
- #[doc(alias = "UARTFR")]
- pub struct Flags {
- /// CTS Clear to send. This bit is the complement of the UART clear to
- /// send, `nUARTCTS`, modem status input. That is, the bit is 1
- /// when `nUARTCTS` is LOW.
- pub clear_to_send: bool,
- /// DSR Data set ready. This bit is the complement of the UART data set
- /// ready, `nUARTDSR`, modem status input. That is, the bit is 1 when
- /// `nUARTDSR` is LOW.
- pub data_set_ready: bool,
- /// DCD Data carrier detect. This bit is the complement of the UART data
- /// carrier detect, `nUARTDCD`, modem status input. That is, the bit is
- /// 1 when `nUARTDCD` is LOW.
- pub data_carrier_detect: bool,
- /// BUSY UART busy. If this bit is set to 1, the UART is busy
- /// transmitting data. This bit remains set until the complete
- /// byte, including all the stop bits, has been sent from the
- /// shift register. This bit is set as soon as the transmit FIFO
- /// becomes non-empty, regardless of whether the UART is enabled
- /// or not.
- pub busy: bool,
- /// RXFE Receive FIFO empty. The meaning of this bit depends on the
- /// state of the FEN bit in the UARTLCR_H register. If the FIFO
- /// is disabled, this bit is set when the receive holding
- /// register is empty. If the FIFO is enabled, the RXFE bit is
- /// set when the receive FIFO is empty.
- pub receive_fifo_empty: bool,
- /// TXFF Transmit FIFO full. The meaning of this bit depends on the
- /// state of the FEN bit in the UARTLCR_H register. If the FIFO
- /// is disabled, this bit is set when the transmit holding
- /// register is full. If the FIFO is enabled, the TXFF bit is
- /// set when the transmit FIFO is full.
- pub transmit_fifo_full: bool,
- /// RXFF Receive FIFO full. The meaning of this bit depends on the state
- /// of the FEN bit in the UARTLCR_H register. If the FIFO is
- /// disabled, this bit is set when the receive holding register
- /// is full. If the FIFO is enabled, the RXFF bit is set when
- /// the receive FIFO is full.
- pub receive_fifo_full: bool,
- /// Transmit FIFO empty. The meaning of this bit depends on the state of
- /// the FEN bit in the [Line Control register](LineControl),
- /// `UARTLCR_H`. If the FIFO is disabled, this bit is set when the
- /// transmit holding register is empty. If the FIFO is enabled,
- /// the TXFE bit is set when the transmit FIFO is empty. This
- /// bit does not indicate if there is data in the transmit shift
- /// register.
- pub transmit_fifo_empty: bool,
- /// `RI`, is `true` when `nUARTRI` is `LOW`.
- pub ring_indicator: bool,
- _reserved_zero_no_modify: u7,
- }
-
- impl Flags {
- pub fn reset(&mut self) {
- // After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1
- self.set_receive_fifo_full(false);
- self.set_transmit_fifo_full(false);
- self.set_busy(false);
- self.set_receive_fifo_empty(true);
- self.set_transmit_fifo_empty(true);
- }
- }
-
- impl Default for Flags {
- fn default() -> Self {
- let mut ret: Self = 0.into();
- ret.reset();
- ret
- }
- }
-
- #[bitsize(16)]
- #[derive(Clone, Copy, DebugBits, FromBits)]
- /// Line Control Register, `UARTLCR_H`
- #[doc(alias = "UARTLCR_H")]
- pub struct LineControl {
- /// 15:8 - Reserved, do not modify, read as zero.
- _reserved_zero_no_modify: u8,
- /// 7 SPS Stick parity select.
- /// 0 = stick parity is disabled
- /// 1 = either:
- /// • if the EPS bit is 0 then the parity bit is transmitted and checked
- /// as a 1 • if the EPS bit is 1 then the parity bit is
- /// transmitted and checked as a 0. This bit has no effect when
- /// the PEN bit disables parity checking and generation. See Table 3-11
- /// on page 3-14 for the parity truth table.
- pub sticky_parity: bool,
- /// WLEN Word length. These bits indicate the number of data bits
- /// transmitted or received in a frame as follows: b11 = 8 bits
- /// b10 = 7 bits
- /// b01 = 6 bits
- /// b00 = 5 bits.
- pub word_length: WordLength,
- /// FEN Enable FIFOs:
- /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
- /// 1-byte-deep holding registers 1 = transmit and receive FIFO
- /// buffers are enabled (FIFO mode).
- pub fifos_enabled: Mode,
- /// 3 STP2 Two stop bits select. If this bit is set to 1, two stop bits
- /// are transmitted at the end of the frame. The receive
- /// logic does not check for two stop bits being received.
- pub two_stops_bits: bool,
- /// EPS Even parity select. Controls the type of parity the UART uses
- /// during transmission and reception:
- /// - 0 = odd parity. The UART generates or checks for an odd number of
- /// 1s in the data and parity bits.
- /// - 1 = even parity. The UART generates or checks for an even number
- /// of 1s in the data and parity bits.
- /// This bit has no effect when the `PEN` bit disables parity checking
- /// and generation. See Table 3-11 on page 3-14 for the parity
- /// truth table.
- pub parity: Parity,
- /// 1 PEN Parity enable:
- ///
- /// - 0 = parity is disabled and no parity bit added to the data frame
- /// - 1 = parity checking and generation is enabled.
- ///
- /// See Table 3-11 on page 3-14 for the parity truth table.
- pub parity_enabled: bool,
- /// BRK Send break.
- ///
- /// If this bit is set to `1`, a low-level is continually output on the
- /// `UARTTXD` output, after completing transmission of the
- /// current character. For the proper execution of the break command,
- /// the software must set this bit for at least two complete
- /// frames. For normal use, this bit must be cleared to `0`.
- pub send_break: bool,
- }
-
- impl LineControl {
- pub fn reset(&mut self) {
- // All the bits are cleared to 0 when reset.
- *self = 0.into();
- }
- }
-
- impl Default for LineControl {
- fn default() -> Self {
- 0.into()
- }
- }
-
- #[bitsize(1)]
- #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
- /// `EPS` "Even parity select", field of [Line Control
- /// register](LineControl).
- pub enum Parity {
- /// - 0 = odd parity. The UART generates or checks for an odd number of
- /// 1s in the data and parity bits.
- Odd = 0,
- /// - 1 = even parity. The UART generates or checks for an even number
- /// of 1s in the data and parity bits.
- Even = 1,
- }
-
- #[bitsize(1)]
- #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
- /// `FEN` "Enable FIFOs" or Device mode, field of [Line Control
- /// register](LineControl).
- pub enum Mode {
- /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
- /// 1-byte-deep holding registers
- Character = 0,
- /// 1 = transmit and receive FIFO buffers are enabled (FIFO mode).
- FIFO = 1,
- }
-
- impl From<Mode> for bool {
- fn from(val: Mode) -> Self {
- matches!(val, Mode::FIFO)
- }
- }
-
- #[bitsize(2)]
- #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
- /// `WLEN` Word length, field of [Line Control register](LineControl).
- ///
- /// These bits indicate the number of data bits transmitted or received in a
- /// frame as follows:
- pub enum WordLength {
- /// b11 = 8 bits
- _8Bits = 0b11,
- /// b10 = 7 bits
- _7Bits = 0b10,
- /// b01 = 6 bits
- _6Bits = 0b01,
- /// b00 = 5 bits.
- _5Bits = 0b00,
- }
-
- /// Control Register, `UARTCR`
- ///
- /// The `UARTCR` register is the control register. All the bits are cleared
- /// to `0` on reset except for bits `9` and `8` that are set to `1`.
- ///
- /// # Source
- /// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
- #[bitsize(16)]
- #[doc(alias = "UARTCR")]
- #[derive(Clone, Copy, DebugBits, FromBits)]
- pub struct Control {
- /// `UARTEN` UART enable: 0 = UART is disabled. If the UART is disabled
- /// in the middle of transmission or reception, it completes the current
- /// character before stopping. 1 = the UART is enabled. Data
- /// transmission and reception occurs for either UART signals or SIR
- /// signals depending on the setting of the SIREN bit.
- pub enable_uart: bool,
- /// `SIREN` `SIR` enable: 0 = IrDA SIR ENDEC is disabled. `nSIROUT`
- /// remains LOW (no light pulse generated), and signal transitions on
- /// SIRIN have no effect. 1 = IrDA SIR ENDEC is enabled. Data is
- /// transmitted and received on nSIROUT and SIRIN. UARTTXD remains HIGH,
- /// in the marking state. Signal transitions on UARTRXD or modem status
- /// inputs have no effect. This bit has no effect if the UARTEN bit
- /// disables the UART.
- pub enable_sir: bool,
- /// `SIRLP` SIR low-power IrDA mode. This bit selects the IrDA encoding
- /// mode. If this bit is cleared to 0, low-level bits are transmitted as
- /// an active high pulse with a width of 3/ 16th of the bit period. If
- /// this bit is set to 1, low-level bits are transmitted with a pulse
- /// width that is 3 times the period of the IrLPBaud16 input signal,
- /// regardless of the selected bit rate. Setting this bit uses less
- /// power, but might reduce transmission distances.
- pub sir_lowpower_irda_mode: u1,
- /// Reserved, do not modify, read as zero.
- _reserved_zero_no_modify: u4,
- /// `LBE` Loopback enable. If this bit is set to 1 and the SIREN bit is
- /// set to 1 and the SIRTEST bit in the Test Control register, UARTTCR
- /// on page 4-5 is set to 1, then the nSIROUT path is inverted, and fed
- /// through to the SIRIN path. The SIRTEST bit in the test register must
- /// be set to 1 to override the normal half-duplex SIR operation. This
- /// must be the requirement for accessing the test registers during
- /// normal operation, and SIRTEST must be cleared to 0 when loopback
- /// testing is finished. This feature reduces the amount of external
- /// coupling required during system test. If this bit is set to 1, and
- /// the SIRTEST bit is set to 0, the UARTTXD path is fed through to the
- /// UARTRXD path. In either SIR mode or UART mode, when this bit is set,
- /// the modem outputs are also fed through to the modem inputs. This bit
- /// is cleared to 0 on reset, to disable loopback.
- pub enable_loopback: bool,
- /// `TXE` Transmit enable. If this bit is set to 1, the transmit section
- /// of the UART is enabled. Data transmission occurs for either UART
- /// signals, or SIR signals depending on the setting of the SIREN bit.
- /// When the UART is disabled in the middle of transmission, it
- /// completes the current character before stopping.
- pub enable_transmit: bool,
- /// `RXE` Receive enable. If this bit is set to 1, the receive section
- /// of the UART is enabled. Data reception occurs for either UART
- /// signals or SIR signals depending on the setting of the SIREN bit.
- /// When the UART is disabled in the middle of reception, it completes
- /// the current character before stopping.
- pub enable_receive: bool,
- /// `DTR` Data transmit ready. This bit is the complement of the UART
- /// data transmit ready, `nUARTDTR`, modem status output. That is, when
- /// the bit is programmed to a 1 then `nUARTDTR` is LOW.
- pub data_transmit_ready: bool,
- /// `RTS` Request to send. This bit is the complement of the UART
- /// request to send, `nUARTRTS`, modem status output. That is, when the
- /// bit is programmed to a 1 then `nUARTRTS` is LOW.
- pub request_to_send: bool,
- /// `Out1` This bit is the complement of the UART Out1 (`nUARTOut1`)
- /// modem status output. That is, when the bit is programmed to a 1 the
- /// output is 0. For DTE this can be used as Data Carrier Detect (DCD).
- pub out_1: bool,
- /// `Out2` This bit is the complement of the UART Out2 (`nUARTOut2`)
- /// modem status output. That is, when the bit is programmed to a 1, the
- /// output is 0. For DTE this can be used as Ring Indicator (RI).
- pub out_2: bool,
- /// `RTSEn` RTS hardware flow control enable. If this bit is set to 1,
- /// RTS hardware flow control is enabled. Data is only requested when
- /// there is space in the receive FIFO for it to be received.
- pub rts_hardware_flow_control_enable: bool,
- /// `CTSEn` CTS hardware flow control enable. If this bit is set to 1,
- /// CTS hardware flow control is enabled. Data is only transmitted when
- /// the `nUARTCTS` signal is asserted.
- pub cts_hardware_flow_control_enable: bool,
- }
-
- impl Control {
- pub fn reset(&mut self) {
- *self = 0.into();
- self.set_enable_receive(true);
- self.set_enable_transmit(true);
- }
- }
-
- impl Default for Control {
- fn default() -> Self {
- let mut ret: Self = 0.into();
- ret.reset();
- ret
- }
- }
-
- /// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
- pub const INT_OE: u32 = 1 << 10;
- pub const INT_BE: u32 = 1 << 9;
- pub const INT_PE: u32 = 1 << 8;
- pub const INT_FE: u32 = 1 << 7;
- pub const INT_RT: u32 = 1 << 6;
- pub const INT_TX: u32 = 1 << 5;
- pub const INT_RX: u32 = 1 << 4;
- pub const INT_DSR: u32 = 1 << 3;
- pub const INT_DCD: u32 = 1 << 2;
- pub const INT_CTS: u32 = 1 << 1;
- pub const INT_RI: u32 = 1 << 0;
- pub const INT_E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
- pub const INT_MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
-
- #[repr(u32)]
- pub enum Interrupt {
- OE = 1 << 10,
- BE = 1 << 9,
- PE = 1 << 8,
- FE = 1 << 7,
- RT = 1 << 6,
- TX = 1 << 5,
- RX = 1 << 4,
- DSR = 1 << 3,
- DCD = 1 << 2,
- CTS = 1 << 1,
- RI = 1 << 0,
- }
-
- impl Interrupt {
- pub const E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
- pub const MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
- }
-}
-
-// TODO: You must disable the UART before any of the control registers are
-// reprogrammed. When the UART is disabled in the middle of transmission or
-// reception, it completes the current character before stopping
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
deleted file mode 100644
index 8d066ebf6d0..00000000000
--- a/rust/hw/char/pl011/src/memory_ops.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2024, Linaro Limited
-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-use core::{mem::MaybeUninit, ptr::NonNull};
-
-use qemu_api::bindings::*;
-
-use crate::device::PL011State;
-
-pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps {
- read: Some(pl011_read),
- write: Some(pl011_write),
- read_with_attrs: None,
- write_with_attrs: None,
- endianness: device_endian::DEVICE_NATIVE_ENDIAN,
- valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() },
- impl_: MemoryRegionOps__bindgen_ty_2 {
- min_access_size: 4,
- max_access_size: 4,
- ..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() }
- },
-};
-
-#[no_mangle]
-unsafe extern "C" fn pl011_read(
- opaque: *mut core::ffi::c_void,
- addr: hwaddr,
- size: core::ffi::c_uint,
-) -> u64 {
- assert!(!opaque.is_null());
- let mut state = unsafe { NonNull::new_unchecked(opaque.cast::<PL011State>()) };
- let val = unsafe { state.as_mut().read(addr, size) };
- match val {
- std::ops::ControlFlow::Break(val) => val,
- std::ops::ControlFlow::Continue(val) => {
- // SAFETY: self.char_backend is a valid CharBackend instance after it's been
- // initialized in realize().
- let cb_ptr = unsafe { core::ptr::addr_of_mut!(state.as_mut().char_backend) };
- unsafe { qemu_chr_fe_accept_input(cb_ptr) };
-
- val
- }
- }
-}
-
-#[no_mangle]
-unsafe extern "C" fn pl011_write(
- opaque: *mut core::ffi::c_void,
- addr: hwaddr,
- data: u64,
- _size: core::ffi::c_uint,
-) {
- unsafe {
- assert!(!opaque.is_null());
- let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
- state.as_mut().write(addr, data)
- }
-}
diff --git a/rust/hw/meson.build b/rust/hw/meson.build
deleted file mode 100644
index 860196645e7..00000000000
--- a/rust/hw/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-subdir('char')
diff --git a/rust/meson.build b/rust/meson.build
index def77389cdd..7a32b1b1950 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -1,4 +1,2 @@
subdir('qemu-api-macros')
subdir('qemu-api')
-
-subdir('hw')
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 30677c3ec90..62a2cf45d28 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -27,9 +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 arbitrary-int-1-rs bilge-0.2-rs
- bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
- proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
+ berkeley-testfloat-3 proc-macro2-1-rs quote-1-rs
syn-2-rs unicode-ident-1-rs"
sub_deinit=""
diff --git a/scripts/make-release b/scripts/make-release
index 8dc939124c4..cf7d694ef73 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -18,9 +18,7 @@ fi
# Only include wraps that are invoked with subproject()
SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
- berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
- bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
- proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
+ berkeley-testfloat-3 proc-macro2-1-rs quote-1-rs
syn-2-rs unicode-ident-1-rs"
src="$1"
diff --git a/scripts/rust/rust_root_crate.sh b/scripts/rust/rust_root_crate.sh
deleted file mode 100755
index 975bddf7f1a..00000000000
--- a/scripts/rust/rust_root_crate.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-
-set -eu
-
-cat <<EOF
-// @generated
-// This file is autogenerated by scripts/rust_root_crate.sh
-
-EOF
-
-for crate in $*; do
- echo "extern crate $crate;"
-done
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index 50f173f90db..b6888182ca4 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -6,13 +6,6 @@
/keycodemapdb
/libvfio-user
/slirp
-/arbitrary-int-1.2.7
-/bilge-0.2.0
-/bilge-impl-0.2.0
-/either-1.12.0
-/itertools-0.11.0
-/proc-macro-error-1.0.4
-/proc-macro-error-attr-1.0.4
/proc-macro2-1.0.84
/quote-1.0.36
/syn-2.0.66
diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap
deleted file mode 100644
index e580538a877..00000000000
--- a/subprojects/arbitrary-int-1-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = arbitrary-int-1.2.7
-source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download
-source_filename = arbitrary-int-1.2.7.tar.gz
-source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d
-#method = cargo
-patch_directory = arbitrary-int-1-rs
diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap
deleted file mode 100644
index 7a4339d2989..00000000000
--- a/subprojects/bilge-0.2-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = bilge-0.2.0
-source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download
-source_filename = bilge-0.2.0.tar.gz
-source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57
-#method = cargo
-patch_directory = bilge-0.2-rs
diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap
deleted file mode 100644
index eefb10c36c2..00000000000
--- a/subprojects/bilge-impl-0.2-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = bilge-impl-0.2.0
-source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download
-source_filename = bilge-impl-0.2.0.tar.gz
-source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8
-#method = cargo
-patch_directory = bilge-impl-0.2-rs
diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap
deleted file mode 100644
index 6046712036c..00000000000
--- a/subprojects/either-1-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = either-1.12.0
-source_url = https://crates.io/api/v1/crates/either/1.12.0/download
-source_filename = either-1.12.0.tar.gz
-source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b
-#method = cargo
-patch_directory = either-1-rs
diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap
deleted file mode 100644
index 66b05252cd5..00000000000
--- a/subprojects/itertools-0.11-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = itertools-0.11.0
-source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download
-source_filename = itertools-0.11.0.tar.gz
-source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57
-#method = cargo
-patch_directory = itertools-0.11-rs
diff --git a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
deleted file mode 100644
index 34a189cbaec..00000000000
--- a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
+++ /dev/null
@@ -1,19 +0,0 @@
-project('arbitrary-int-1-rs', 'rust',
- version: '1.2.7',
- license: 'MIT',
- default_options: [])
-
-_arbitrary_int_rs = static_library(
- 'arbitrary_int',
- files('src/lib.rs'),
- gnu_symbol_visibility: 'hidden',
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_abi: 'rust',
- dependencies: [],
-)
-
-arbitrary_int_dep = declare_dependency(
- link_with: _arbitrary_int_rs,
-)
-
-meson.override_dependency('arbitrary-int-1-rs', arbitrary_int_dep)
diff --git a/subprojects/packagefiles/bilge-0.2-rs/meson.build b/subprojects/packagefiles/bilge-0.2-rs/meson.build
deleted file mode 100644
index a6ed4a8f0cd..00000000000
--- a/subprojects/packagefiles/bilge-0.2-rs/meson.build
+++ /dev/null
@@ -1,29 +0,0 @@
-project(
- 'bilge-0.2-rs',
- 'rust',
- version : '0.2.0',
- license : 'MIT or Apache-2.0',
-)
-
-subproject('arbitrary-int-1-rs', required: true)
-subproject('bilge-impl-0.2-rs', required: true)
-
-arbitrary_int_dep = dependency('arbitrary-int-1-rs')
-bilge_impl_dep = dependency('bilge-impl-0.2-rs')
-
-lib = static_library(
- 'bilge',
- 'src/lib.rs',
- override_options : ['rust_std=2021', 'build.rust_std=2021'],
- rust_abi : 'rust',
- dependencies: [
- arbitrary_int_dep,
- bilge_impl_dep,
- ],
-)
-
-bilge_dep = declare_dependency(
- link_with : [lib],
-)
-
-meson.override_dependency('bilge-0.2-rs', bilge_dep)
diff --git a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
deleted file mode 100644
index 80243c7024d..00000000000
--- a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
+++ /dev/null
@@ -1,45 +0,0 @@
-project('bilge-impl-0.2-rs', 'rust',
- version: '0.2.0',
- license: 'MIT OR Apache-2.0',
- default_options: [])
-
-subproject('itertools-0.11-rs', required: true)
-subproject('proc-macro-error-attr-1-rs', required: true)
-subproject('proc-macro-error-1-rs', required: true)
-subproject('quote-1-rs', required: true)
-subproject('syn-2-rs', required: true)
-subproject('proc-macro2-1-rs', required: true)
-
-itertools_dep = dependency('itertools-0.11-rs', native: true)
-proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
-proc_macro_error_dep = dependency('proc-macro-error-1-rs', native: true)
-quote_dep = dependency('quote-1-rs', native: true)
-syn_dep = dependency('syn-2-rs', native: true)
-proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
-
-rust = import('rust')
-
-_bilge_impl_rs = rust.proc_macro(
- 'bilge_impl',
- files('src/lib.rs'),
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_args: [
- '--cfg', 'use_fallback',
- '--cfg', 'feature="syn-error"',
- '--cfg', 'feature="proc-macro"',
- ],
- dependencies: [
- itertools_dep,
- proc_macro_error_attr_dep,
- proc_macro_error_dep,
- quote_dep,
- syn_dep,
- proc_macro2_dep,
- ],
-)
-
-bilge_impl_dep = declare_dependency(
- link_with: _bilge_impl_rs,
-)
-
-meson.override_dependency('bilge-impl-0.2-rs', bilge_impl_dep)
diff --git a/subprojects/packagefiles/either-1-rs/meson.build b/subprojects/packagefiles/either-1-rs/meson.build
deleted file mode 100644
index a5842eb3a6a..00000000000
--- a/subprojects/packagefiles/either-1-rs/meson.build
+++ /dev/null
@@ -1,24 +0,0 @@
-project('either-1-rs', 'rust',
- version: '1.12.0',
- license: 'MIT OR Apache-2.0',
- default_options: [])
-
-_either_rs = static_library(
- 'either',
- files('src/lib.rs'),
- gnu_symbol_visibility: 'hidden',
- override_options: ['rust_std=2018', 'build.rust_std=2018'],
- rust_abi: 'rust',
- rust_args: [
- '--cfg', 'feature="use_std"',
- '--cfg', 'feature="use_alloc"',
- ],
- dependencies: [],
- native: true,
-)
-
-either_dep = declare_dependency(
- link_with: _either_rs,
-)
-
-meson.override_dependency('either-1-rs', either_dep, native: true)
diff --git a/subprojects/packagefiles/itertools-0.11-rs/meson.build b/subprojects/packagefiles/itertools-0.11-rs/meson.build
deleted file mode 100644
index 13d2d27019d..00000000000
--- a/subprojects/packagefiles/itertools-0.11-rs/meson.build
+++ /dev/null
@@ -1,30 +0,0 @@
-project('itertools-0.11-rs', 'rust',
- version: '0.11.0',
- license: 'MIT OR Apache-2.0',
- default_options: [])
-
-subproject('either-1-rs', required: true)
-
-either_dep = dependency('either-1-rs', native: true)
-
-_itertools_rs = static_library(
- 'itertools',
- files('src/lib.rs'),
- gnu_symbol_visibility: 'hidden',
- override_options: ['rust_std=2018', 'build.rust_std=2018'],
- rust_abi: 'rust',
- rust_args: [
- '--cfg', 'feature="use_std"',
- '--cfg', 'feature="use_alloc"',
- ],
- dependencies: [
- either_dep,
- ],
- native: true,
-)
-
-itertools_dep = declare_dependency(
- link_with: _itertools_rs,
-)
-
-meson.override_dependency('itertools-0.11-rs', itertools_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
deleted file mode 100644
index 38ea7b89d39..00000000000
--- a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
+++ /dev/null
@@ -1,40 +0,0 @@
-project('proc-macro-error-1-rs', 'rust',
- version: '1.0.4',
- license: 'MIT OR Apache-2.0',
- default_options: [])
-
-subproject('proc-macro-error-attr-1-rs', required: true)
-subproject('quote-1-rs', required: true)
-subproject('syn-2-rs', required: true)
-subproject('proc-macro2-1-rs', required: true)
-
-proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
-proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
-quote_dep = dependency('quote-1-rs', native: true)
-syn_dep = dependency('syn-2-rs', native: true)
-
-_proc_macro_error_rs = static_library(
- 'proc_macro_error',
- files('src/lib.rs'),
- override_options: ['rust_std=2018', 'build.rust_std=2018'],
- rust_abi: 'rust',
- rust_args: [
- '--cfg', 'use_fallback',
- '--cfg', 'feature="syn-error"',
- '--cfg', 'feature="proc-macro"',
- '-A', 'non_fmt_panics'
- ],
- dependencies: [
- proc_macro_error_attr_dep,
- proc_macro2_dep,
- quote_dep,
- syn_dep,
- ],
- native: true,
-)
-
-proc_macro_error_dep = declare_dependency(
- link_with: _proc_macro_error_rs,
-)
-
-meson.override_dependency('proc-macro-error-1-rs', proc_macro_error_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
deleted file mode 100644
index d900c54cfd1..00000000000
--- a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
+++ /dev/null
@@ -1,32 +0,0 @@
-project('proc-macro-error-attr-1-rs', 'rust',
- version: '1.12.0',
- license: 'MIT OR Apache-2.0',
- default_options: [])
-
-subproject('proc-macro2-1-rs', required: true)
-subproject('quote-1-rs', required: true)
-
-proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
-quote_dep = dependency('quote-1-rs', native: true)
-
-rust = import('rust')
-_proc_macro_error_attr_rs = rust.proc_macro(
- 'proc_macro_error_attr',
- files('src/lib.rs'),
- override_options: ['rust_std=2018', 'build.rust_std=2018'],
- rust_args: [
- '--cfg', 'use_fallback',
- '--cfg', 'feature="syn-error"',
- '--cfg', 'feature="proc-macro"'
- ],
- dependencies: [
- proc_macro2_dep,
- quote_dep,
- ],
-)
-
-proc_macro_error_attr_dep = declare_dependency(
- link_with: _proc_macro_error_attr_rs,
-)
-
-meson.override_dependency('proc-macro-error-attr-1-rs', proc_macro_error_attr_dep, native: true)
diff --git a/subprojects/packagefiles/unicode-ident-1-rs/meson.build b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
deleted file mode 100644
index 54f23768545..00000000000
--- a/subprojects/packagefiles/unicode-ident-1-rs/meson.build
+++ /dev/null
@@ -1,20 +0,0 @@
-project('unicode-ident-1-rs', 'rust',
- version: '1.0.12',
- license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
- default_options: [])
-
-_unicode_ident_rs = static_library(
- 'unicode_ident',
- files('src/lib.rs'),
- gnu_symbol_visibility: 'hidden',
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_abi: 'rust',
- dependencies: [],
- native: true,
-)
-
-unicode_ident_dep = declare_dependency(
- link_with: _unicode_ident_rs,
-)
-
-meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap
deleted file mode 100644
index b7db03b06a0..00000000000
--- a/subprojects/proc-macro-error-1-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = proc-macro-error-1.0.4
-source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download
-source_filename = proc-macro-error-1.0.4.tar.gz
-source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c
-#method = cargo
-patch_directory = proc-macro-error-1-rs
diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap
deleted file mode 100644
index d13d8a239ac..00000000000
--- a/subprojects/proc-macro-error-attr-1-rs.wrap
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrap-file]
-directory = proc-macro-error-attr-1.0.4
-source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download
-source_filename = proc-macro-error-attr-1.0.4.tar.gz
-source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869
-#method = cargo
-patch_directory = proc-macro-error-attr-1-rs
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 04/40] rust: add PL011 device model
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (2 preceding siblings ...)
2024-11-04 17:26 ` [PULL 03/40] Revert "rust: add PL011 device model" Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 05/40] meson: import rust module into a global variable Paolo Bonzini
` (36 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu, Junjie Mao
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit adds a re-implementation of hw/char/pl011.c in Rust.
How to build:
1. Configure a QEMU build with:
--enable-system --target-list=aarch64-softmmu --enable-rust
2. Launching a VM with qemu-system-aarch64 should use the Rust version
of the pl011 device
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: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-2-051e7a25b978@linaro.org
---
MAINTAINERS | 5 +
meson.build | 24 +
hw/arm/Kconfig | 30 +-
rust/Kconfig | 1 +
rust/hw/Kconfig | 2 +
rust/hw/char/Kconfig | 3 +
rust/hw/char/meson.build | 1 +
rust/hw/char/pl011/.gitignore | 2 +
rust/hw/char/pl011/Cargo.lock | 134 ++++
rust/hw/char/pl011/Cargo.toml | 26 +
rust/hw/char/pl011/README.md | 31 +
rust/hw/char/pl011/meson.build | 26 +
rust/hw/char/pl011/src/device.rs | 599 ++++++++++++++++++
rust/hw/char/pl011/src/device_class.rs | 70 ++
rust/hw/char/pl011/src/lib.rs | 586 +++++++++++++++++
rust/hw/char/pl011/src/memory_ops.rs | 59 ++
rust/hw/meson.build | 1 +
rust/meson.build | 2 +
scripts/archive-source.sh | 4 +-
scripts/make-release | 4 +-
scripts/rust/rust_root_crate.sh | 13 +
subprojects/.gitignore | 7 +
subprojects/arbitrary-int-1-rs.wrap | 7 +
subprojects/bilge-0.2-rs.wrap | 7 +
subprojects/bilge-impl-0.2-rs.wrap | 7 +
subprojects/either-1-rs.wrap | 7 +
subprojects/itertools-0.11-rs.wrap | 7 +
.../arbitrary-int-1-rs/meson.build | 19 +
.../packagefiles/bilge-0.2-rs/meson.build | 29 +
.../bilge-impl-0.2-rs/meson.build | 45 ++
.../packagefiles/either-1-rs/meson.build | 24 +
.../itertools-0.11-rs/meson.build | 30 +
.../proc-macro-error-1-rs/meson.build | 40 ++
.../proc-macro-error-attr-1-rs/meson.build | 32 +
.../unicode-ident-1-rs/meson.build | 20 +
subprojects/proc-macro-error-1-rs.wrap | 7 +
subprojects/proc-macro-error-attr-1-rs.wrap | 7 +
37 files changed, 1906 insertions(+), 12 deletions(-)
create mode 100644 rust/hw/Kconfig
create mode 100644 rust/hw/char/Kconfig
create mode 100644 rust/hw/char/meson.build
create mode 100644 rust/hw/char/pl011/.gitignore
create mode 100644 rust/hw/char/pl011/Cargo.lock
create mode 100644 rust/hw/char/pl011/Cargo.toml
create mode 100644 rust/hw/char/pl011/README.md
create mode 100644 rust/hw/char/pl011/meson.build
create mode 100644 rust/hw/char/pl011/src/device.rs
create mode 100644 rust/hw/char/pl011/src/device_class.rs
create mode 100644 rust/hw/char/pl011/src/lib.rs
create mode 100644 rust/hw/char/pl011/src/memory_ops.rs
create mode 100644 rust/hw/meson.build
create mode 100755 scripts/rust/rust_root_crate.sh
create mode 100644 subprojects/arbitrary-int-1-rs.wrap
create mode 100644 subprojects/bilge-0.2-rs.wrap
create mode 100644 subprojects/bilge-impl-0.2-rs.wrap
create mode 100644 subprojects/either-1-rs.wrap
create mode 100644 subprojects/itertools-0.11-rs.wrap
create mode 100644 subprojects/packagefiles/arbitrary-int-1-rs/meson.build
create mode 100644 subprojects/packagefiles/bilge-0.2-rs/meson.build
create mode 100644 subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
create mode 100644 subprojects/packagefiles/either-1-rs/meson.build
create mode 100644 subprojects/packagefiles/itertools-0.11-rs/meson.build
create mode 100644 subprojects/packagefiles/proc-macro-error-1-rs/meson.build
create mode 100644 subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
create mode 100644 subprojects/packagefiles/unicode-ident-1-rs/meson.build
create mode 100644 subprojects/proc-macro-error-1-rs.wrap
create mode 100644 subprojects/proc-macro-error-attr-1-rs.wrap
diff --git a/MAINTAINERS b/MAINTAINERS
index 3f17295d41e..f48d9142b8a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1138,6 +1138,11 @@ F: include/hw/*/microbit*.h
F: tests/qtest/microbit-test.c
F: docs/system/arm/nrf.rst
+ARM PL011 Rust device
+M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+S: Maintained
+F: rust/hw/char/pl011/
+
AVR Machines
-------------
diff --git a/meson.build b/meson.build
index f290bb70b1d..f7d45175212 100644
--- a/meson.build
+++ b/meson.build
@@ -3534,6 +3534,7 @@ qom_ss = ss.source_set()
system_ss = ss.source_set()
specific_fuzz_ss = ss.source_set()
specific_ss = ss.source_set()
+rust_devices_ss = ss.source_set()
stub_ss = ss.source_set()
trace_ss = ss.source_set()
user_ss = ss.source_set()
@@ -4081,6 +4082,29 @@ foreach target : target_dirs
arch_srcs += target_specific.sources()
arch_deps += target_specific.dependencies()
+ if have_rust and have_system
+ target_rust = rust_devices_ss.apply(config_target, strict: false)
+ crates = []
+ foreach dep : target_rust.dependencies()
+ crates += dep.get_variable('crate')
+ endforeach
+ if crates.length() > 0
+ rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
+ output: 'rust_' + target.underscorify() + '.rs',
+ command: [find_program('scripts/rust/rust_root_crate.sh')] + crates,
+ capture: true,
+ build_by_default: true,
+ build_always_stale: true)
+ rlib = static_library('rust_' + target.underscorify(),
+ rlib_rs,
+ dependencies: target_rust.dependencies(),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: rustc_args,
+ rust_abi: 'c')
+ arch_deps += declare_dependency(link_whole: [rlib])
+ endif
+ endif
+
# allow using headers from the dependencies but do not include the sources,
# because this emulator only needs those in "objects". For external
# dependencies, the full dependency is included below in the executable.
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 53eb7bb3d01..e7fd9338d11 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -20,7 +20,8 @@ config ARM_VIRT
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL061 # GPIO
select GPIO_PWR
@@ -73,7 +74,8 @@ config HIGHBANK
select AHCI
select ARM_TIMER # sp804
select ARM_V7M
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL022 # SPI
select PL031 # RTC
select PL061 # GPIO
@@ -86,7 +88,8 @@ config INTEGRATOR
depends on TCG && ARM
select ARM_TIMER
select INTEGRATOR_DEBUG
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL041 # audio
select PL050 # keyboard/mouse
@@ -104,7 +107,8 @@ config MUSCA
default y
depends on TCG && ARM
select ARMSSE
- select PL011
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031
select SPLIT_IRQ
select UNIMP
@@ -168,7 +172,8 @@ config REALVIEW
select WM8750 # audio codec
select LSI_SCSI_PCI
select PCI
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL041 # audio codec
select PL050 # keyboard/mouse
@@ -193,7 +198,8 @@ config SBSA_REF
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL061 # GPIO
select USB_XHCI_SYSBUS
@@ -217,7 +223,8 @@ config STELLARIS
select ARM_V7M
select CMSDK_APB_WATCHDOG
select I2C
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL022 # SPI
select PL061 # GPIO
select SSD0303 # OLED display
@@ -277,7 +284,8 @@ config VEXPRESS
select ARM_TIMER # sp804
select LAN9118
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL041 # audio codec
select PL181 # display
select REALVIEW
@@ -362,7 +370,8 @@ config RASPI
default y
depends on TCG && ARM
select FRAMEBUFFER
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select SDHCI
select USB_DWC2
select BCM2835_SPI
@@ -438,7 +447,8 @@ config XLNX_VERSAL
select ARM_GIC
select CPU_CLUSTER
select DEVICE_TREE
- select PL011
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select CADENCE
select VIRTIO_MMIO
select UNIMP
diff --git a/rust/Kconfig b/rust/Kconfig
index e69de29bb2d..f9f5c390988 100644
--- a/rust/Kconfig
+++ b/rust/Kconfig
@@ -0,0 +1 @@
+source hw/Kconfig
diff --git a/rust/hw/Kconfig b/rust/hw/Kconfig
new file mode 100644
index 00000000000..4d934f30afe
--- /dev/null
+++ b/rust/hw/Kconfig
@@ -0,0 +1,2 @@
+# devices Kconfig
+source char/Kconfig
diff --git a/rust/hw/char/Kconfig b/rust/hw/char/Kconfig
new file mode 100644
index 00000000000..a1732a9e97f
--- /dev/null
+++ b/rust/hw/char/Kconfig
@@ -0,0 +1,3 @@
+config X_PL011_RUST
+ bool
+ default y if HAVE_RUST
diff --git a/rust/hw/char/meson.build b/rust/hw/char/meson.build
new file mode 100644
index 00000000000..5716dc43ef6
--- /dev/null
+++ b/rust/hw/char/meson.build
@@ -0,0 +1 @@
+subdir('pl011')
diff --git a/rust/hw/char/pl011/.gitignore b/rust/hw/char/pl011/.gitignore
new file mode 100644
index 00000000000..71eaff2035d
--- /dev/null
+++ b/rust/hw/char/pl011/.gitignore
@@ -0,0 +1,2 @@
+# Ignore generated bindings file overrides.
+src/bindings.rs.inc
diff --git a/rust/hw/char/pl011/Cargo.lock b/rust/hw/char/pl011/Cargo.lock
new file mode 100644
index 00000000000..b58cebb186e
--- /dev/null
+++ b/rust/hw/char/pl011/Cargo.lock
@@ -0,0 +1,134 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "arbitrary-int"
+version = "1.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
+
+[[package]]
+name = "bilge"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57"
+dependencies = [
+ "arbitrary-int",
+ "bilge-impl",
+]
+
+[[package]]
+name = "bilge-impl"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8"
+dependencies = [
+ "itertools",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+
+[[package]]
+name = "itertools"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "pl011"
+version = "0.1.0"
+dependencies = [
+ "bilge",
+ "bilge-impl",
+ "qemu_api",
+ "qemu_api_macros",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qemu_api"
+version = "0.1.0"
+
+[[package]]
+name = "qemu_api_macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml
new file mode 100644
index 00000000000..b089e3dded6
--- /dev/null
+++ b/rust/hw/char/pl011/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "pl011"
+version = "0.1.0"
+edition = "2021"
+authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
+license = "GPL-2.0-or-later"
+readme = "README.md"
+homepage = "https://www.qemu.org"
+description = "pl011 device model for QEMU"
+repository = "https://gitlab.com/epilys/rust-for-qemu"
+resolver = "2"
+publish = false
+keywords = []
+categories = []
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+bilge = { version = "0.2.0" }
+bilge-impl = { version = "0.2.0" }
+qemu_api = { path = "../../../qemu-api" }
+qemu_api_macros = { path = "../../../qemu-api-macros" }
+
+# Do not include in any global workspace
+[workspace]
diff --git a/rust/hw/char/pl011/README.md b/rust/hw/char/pl011/README.md
new file mode 100644
index 00000000000..cd7dea31634
--- /dev/null
+++ b/rust/hw/char/pl011/README.md
@@ -0,0 +1,31 @@
+# PL011 QEMU Device Model
+
+This library implements a device model for the PrimeCell® UART (PL011)
+device in QEMU.
+
+## Build static lib
+
+Host build target must be explicitly specified:
+
+```sh
+cargo build --target x86_64-unknown-linux-gnu
+```
+
+Replace host target triplet if necessary.
+
+## Generate Rust documentation
+
+To generate docs for this crate, including private items:
+
+```sh
+cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
+```
+
+To include direct dependencies like `bilge` (bitmaps for register types):
+
+```sh
+cargo tree --depth 1 -e normal --prefix none \
+ | cut -d' ' -f1 \
+ | xargs printf -- '-p %s\n' \
+ | xargs cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
+```
diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build
new file mode 100644
index 00000000000..547cca5a96f
--- /dev/null
+++ b/rust/hw/char/pl011/meson.build
@@ -0,0 +1,26 @@
+subproject('bilge-0.2-rs', required: true)
+subproject('bilge-impl-0.2-rs', required: true)
+
+bilge_dep = dependency('bilge-0.2-rs')
+bilge_impl_dep = dependency('bilge-impl-0.2-rs')
+
+_libpl011_rs = static_library(
+ 'pl011',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [
+ bilge_dep,
+ bilge_impl_dep,
+ qemu_api,
+ qemu_api_macros,
+ ],
+)
+
+rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
+ link_whole: [_libpl011_rs],
+ # Putting proc macro crates in `dependencies` is necessary for Meson to find
+ # them when compiling the root per-target static rust lib.
+ dependencies: [bilge_impl_dep, qemu_api_macros],
+ variables: {'crate': 'pl011'},
+)])
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
new file mode 100644
index 00000000000..c7193b41bee
--- /dev/null
+++ b/rust/hw/char/pl011/src/device.rs
@@ -0,0 +1,599 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::{
+ ffi::{c_int, c_uchar, c_uint, c_void, CStr},
+ ptr::{addr_of, addr_of_mut, NonNull},
+};
+
+use qemu_api::{
+ bindings::{self, *},
+ definitions::ObjectImpl,
+};
+
+use crate::{
+ memory_ops::PL011_OPS,
+ registers::{self, Interrupt},
+ RegisterOffset,
+};
+
+static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
+
+const DATA_BREAK: u32 = 1 << 10;
+
+/// QEMU sourced constant.
+pub const PL011_FIFO_DEPTH: usize = 16_usize;
+
+#[repr(C)]
+#[derive(Debug, qemu_api_macros::Object)]
+/// PL011 Device Model in QEMU
+pub struct PL011State {
+ pub parent_obj: SysBusDevice,
+ pub iomem: MemoryRegion,
+ #[doc(alias = "fr")]
+ pub flags: registers::Flags,
+ #[doc(alias = "lcr")]
+ pub line_control: registers::LineControl,
+ #[doc(alias = "rsr")]
+ pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
+ #[doc(alias = "cr")]
+ pub control: registers::Control,
+ pub dmacr: u32,
+ pub int_enabled: u32,
+ pub int_level: u32,
+ pub read_fifo: [u32; PL011_FIFO_DEPTH],
+ pub ilpr: u32,
+ pub ibrd: u32,
+ pub fbrd: u32,
+ pub ifl: u32,
+ pub read_pos: usize,
+ pub read_count: usize,
+ pub read_trigger: usize,
+ #[doc(alias = "chr")]
+ pub char_backend: CharBackend,
+ /// QEMU interrupts
+ ///
+ /// ```text
+ /// * sysbus MMIO region 0: device registers
+ /// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
+ /// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
+ /// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
+ /// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
+ /// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
+ /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
+ /// ```
+ #[doc(alias = "irq")]
+ pub interrupts: [qemu_irq; 6usize],
+ #[doc(alias = "clk")]
+ pub clock: NonNull<Clock>,
+ #[doc(alias = "migrate_clk")]
+ pub migrate_clock: bool,
+}
+
+impl ObjectImpl for PL011State {
+ type Class = PL011Class;
+ const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
+ const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_SYS_BUS_DEVICE);
+ const ABSTRACT: bool = false;
+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = Some(pl011_init);
+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+}
+
+#[repr(C)]
+pub struct PL011Class {
+ _inner: [u8; 0],
+}
+
+impl qemu_api::definitions::Class for PL011Class {
+ const CLASS_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = Some(crate::device_class::pl011_class_init);
+ const CLASS_BASE_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = None;
+}
+
+#[used]
+pub static CLK_NAME: &CStr = c"clk";
+
+impl PL011State {
+ /// Initializes a pre-allocated, unitialized instance of `PL011State`.
+ ///
+ /// # Safety
+ ///
+ /// `self` must point to a correctly sized and aligned location for the
+ /// `PL011State` type. It must not be called more than once on the same
+ /// location/instance. All its fields are expected to hold unitialized
+ /// values with the sole exception of `parent_obj`.
+ pub unsafe fn init(&mut self) {
+ let dev = addr_of_mut!(*self).cast::<DeviceState>();
+ // SAFETY:
+ //
+ // self and self.iomem are guaranteed to be valid at this point since callers
+ // must make sure the `self` reference is valid.
+ unsafe {
+ memory_region_init_io(
+ addr_of_mut!(self.iomem),
+ addr_of_mut!(*self).cast::<Object>(),
+ &PL011_OPS,
+ addr_of_mut!(*self).cast::<c_void>(),
+ Self::TYPE_INFO.name,
+ 0x1000,
+ );
+ let sbd = addr_of_mut!(*self).cast::<SysBusDevice>();
+ sysbus_init_mmio(sbd, addr_of_mut!(self.iomem));
+ for irq in self.interrupts.iter_mut() {
+ sysbus_init_irq(sbd, irq);
+ }
+ }
+ // SAFETY:
+ //
+ // self.clock is not initialized at this point; but since `NonNull<_>` is Copy,
+ // we can overwrite the undefined value without side effects. This is
+ // safe since all PL011State instances are created by QOM code which
+ // calls this function to initialize the fields; therefore no code is
+ // able to access an invalid self.clock value.
+ unsafe {
+ self.clock = NonNull::new(qdev_init_clock_in(
+ dev,
+ CLK_NAME.as_ptr(),
+ None, /* pl011_clock_update */
+ addr_of_mut!(*self).cast::<c_void>(),
+ ClockEvent::ClockUpdate.0,
+ ))
+ .unwrap();
+ }
+ }
+
+ pub fn read(
+ &mut self,
+ offset: hwaddr,
+ _size: core::ffi::c_uint,
+ ) -> std::ops::ControlFlow<u64, u64> {
+ use RegisterOffset::*;
+
+ std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
+ Err(v) if (0x3f8..0x400).contains(&v) => {
+ u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize])
+ }
+ Err(_) => {
+ // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
+ 0
+ }
+ Ok(DR) => {
+ // s->flags &= ~PL011_FLAG_RXFF;
+ self.flags.set_receive_fifo_full(false);
+ let c = self.read_fifo[self.read_pos];
+ if self.read_count > 0 {
+ self.read_count -= 1;
+ self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
+ }
+ if self.read_count == 0 {
+ // self.flags |= PL011_FLAG_RXFE;
+ self.flags.set_receive_fifo_empty(true);
+ }
+ if self.read_count + 1 == self.read_trigger {
+ //self.int_level &= ~ INT_RX;
+ self.int_level &= !registers::INT_RX;
+ }
+ // Update error bits.
+ self.receive_status_error_clear = c.to_be_bytes()[3].into();
+ self.update();
+ // Must call qemu_chr_fe_accept_input, so return Continue:
+ return std::ops::ControlFlow::Continue(c.into());
+ }
+ Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
+ Ok(FR) => u16::from(self.flags).into(),
+ Ok(FBRD) => self.fbrd.into(),
+ Ok(ILPR) => self.ilpr.into(),
+ Ok(IBRD) => self.ibrd.into(),
+ Ok(LCR_H) => u16::from(self.line_control).into(),
+ Ok(CR) => {
+ // We exercise our self-control.
+ u16::from(self.control).into()
+ }
+ Ok(FLS) => self.ifl.into(),
+ Ok(IMSC) => self.int_enabled.into(),
+ Ok(RIS) => self.int_level.into(),
+ Ok(MIS) => u64::from(self.int_level & self.int_enabled),
+ Ok(ICR) => {
+ // "The UARTICR Register is the interrupt clear register and is write-only"
+ // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
+ 0
+ }
+ Ok(DMACR) => self.dmacr.into(),
+ })
+ }
+
+ pub fn write(&mut self, offset: hwaddr, value: u64) {
+ // eprintln!("write offset {offset} value {value}");
+ use RegisterOffset::*;
+ let value: u32 = value as u32;
+ match RegisterOffset::try_from(offset) {
+ Err(_bad_offset) => {
+ eprintln!("write bad offset {offset} value {value}");
+ }
+ Ok(DR) => {
+ // ??? Check if transmitter is enabled.
+ let ch: u8 = value as u8;
+ // XXX this blocks entire thread. Rewrite to use
+ // qemu_chr_fe_write and background I/O callbacks
+
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ unsafe {
+ qemu_chr_fe_write_all(addr_of_mut!(self.char_backend), &ch, 1);
+ }
+ self.loopback_tx(value);
+ self.int_level |= registers::INT_TX;
+ self.update();
+ }
+ Ok(RSR) => {
+ self.receive_status_error_clear = 0.into();
+ }
+ Ok(FR) => {
+ // flag writes are ignored
+ }
+ Ok(ILPR) => {
+ self.ilpr = value;
+ }
+ Ok(IBRD) => {
+ self.ibrd = value;
+ }
+ Ok(FBRD) => {
+ self.fbrd = value;
+ }
+ Ok(LCR_H) => {
+ let value = value as u16;
+ let new_val: registers::LineControl = value.into();
+ // Reset the FIFO state on FIFO enable or disable
+ if bool::from(self.line_control.fifos_enabled())
+ ^ bool::from(new_val.fifos_enabled())
+ {
+ self.reset_fifo();
+ }
+ if self.line_control.send_break() ^ new_val.send_break() {
+ let mut break_enable: c_int = new_val.send_break().into();
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ unsafe {
+ qemu_chr_fe_ioctl(
+ addr_of_mut!(self.char_backend),
+ CHR_IOCTL_SERIAL_SET_BREAK as i32,
+ addr_of_mut!(break_enable).cast::<c_void>(),
+ );
+ }
+ self.loopback_break(break_enable > 0);
+ }
+ self.line_control = new_val;
+ self.set_read_trigger();
+ }
+ Ok(CR) => {
+ // ??? Need to implement the enable bit.
+ let value = value as u16;
+ self.control = value.into();
+ self.loopback_mdmctrl();
+ }
+ Ok(FLS) => {
+ self.ifl = value;
+ self.set_read_trigger();
+ }
+ Ok(IMSC) => {
+ self.int_enabled = value;
+ self.update();
+ }
+ Ok(RIS) => {}
+ Ok(MIS) => {}
+ Ok(ICR) => {
+ self.int_level &= !value;
+ self.update();
+ }
+ Ok(DMACR) => {
+ self.dmacr = value;
+ if value & 3 > 0 {
+ // qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
+ eprintln!("pl011: DMA not implemented");
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn loopback_tx(&mut self, value: u32) {
+ if !self.loopback_enabled() {
+ return;
+ }
+
+ // Caveat:
+ //
+ // In real hardware, TX loopback happens at the serial-bit level
+ // and then reassembled by the RX logics back into bytes and placed
+ // into the RX fifo. That is, loopback happens after TX fifo.
+ //
+ // Because the real hardware TX fifo is time-drained at the frame
+ // rate governed by the configured serial format, some loopback
+ // bytes in TX fifo may still be able to get into the RX fifo
+ // that could be full at times while being drained at software
+ // pace.
+ //
+ // In such scenario, the RX draining pace is the major factor
+ // deciding which loopback bytes get into the RX fifo, unless
+ // hardware flow-control is enabled.
+ //
+ // For simplicity, the above described is not emulated.
+ self.put_fifo(value);
+ }
+
+ fn loopback_mdmctrl(&mut self) {
+ if !self.loopback_enabled() {
+ return;
+ }
+
+ /*
+ * Loopback software-driven modem control outputs to modem status inputs:
+ * FR.RI <= CR.Out2
+ * FR.DCD <= CR.Out1
+ * FR.CTS <= CR.RTS
+ * FR.DSR <= CR.DTR
+ *
+ * The loopback happens immediately even if this call is triggered
+ * by setting only CR.LBE.
+ *
+ * CTS/RTS updates due to enabled hardware flow controls are not
+ * dealt with here.
+ */
+
+ //fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
+ // PL011_FLAG_DSR | PL011_FLAG_CTS);
+ //fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
+ //fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
+ //fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
+ //fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
+ //
+ self.flags.set_ring_indicator(self.control.out_2());
+ self.flags.set_data_carrier_detect(self.control.out_1());
+ self.flags.set_clear_to_send(self.control.request_to_send());
+ self.flags
+ .set_data_set_ready(self.control.data_transmit_ready());
+
+ // Change interrupts based on updated FR
+ let mut il = self.int_level;
+
+ il &= !Interrupt::MS;
+ //il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
+ //il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
+ //il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
+ //il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
+
+ if self.flags.data_set_ready() {
+ il |= Interrupt::DSR as u32;
+ }
+ if self.flags.data_carrier_detect() {
+ il |= Interrupt::DCD as u32;
+ }
+ if self.flags.clear_to_send() {
+ il |= Interrupt::CTS as u32;
+ }
+ if self.flags.ring_indicator() {
+ il |= Interrupt::RI as u32;
+ }
+ self.int_level = il;
+ self.update();
+ }
+
+ fn loopback_break(&mut self, enable: bool) {
+ if enable {
+ self.loopback_tx(DATA_BREAK);
+ }
+ }
+
+ fn set_read_trigger(&mut self) {
+ self.read_trigger = 1;
+ }
+
+ pub fn realize(&mut self) {
+ // SAFETY: self.char_backend has the correct size and alignment for a
+ // CharBackend object, and its callbacks are of the correct types.
+ unsafe {
+ qemu_chr_fe_set_handlers(
+ addr_of_mut!(self.char_backend),
+ Some(pl011_can_receive),
+ Some(pl011_receive),
+ Some(pl011_event),
+ None,
+ addr_of_mut!(*self).cast::<c_void>(),
+ core::ptr::null_mut(),
+ true,
+ );
+ }
+ }
+
+ pub fn reset(&mut self) {
+ self.line_control.reset();
+ self.receive_status_error_clear.reset();
+ self.dmacr = 0;
+ self.int_enabled = 0;
+ self.int_level = 0;
+ self.ilpr = 0;
+ self.ibrd = 0;
+ self.fbrd = 0;
+ self.read_trigger = 1;
+ self.ifl = 0x12;
+ self.control.reset();
+ self.flags = 0.into();
+ self.reset_fifo();
+ }
+
+ pub fn reset_fifo(&mut self) {
+ self.read_count = 0;
+ self.read_pos = 0;
+
+ /* Reset FIFO flags */
+ self.flags.reset();
+ }
+
+ pub fn can_receive(&self) -> bool {
+ // trace_pl011_can_receive(s->lcr, s->read_count, r);
+ self.read_count < self.fifo_depth()
+ }
+
+ pub fn event(&mut self, event: QEMUChrEvent) {
+ if event == bindings::QEMUChrEvent::CHR_EVENT_BREAK && !self.fifo_enabled() {
+ self.put_fifo(DATA_BREAK);
+ self.receive_status_error_clear.set_break_error(true);
+ }
+ }
+
+ #[inline]
+ pub fn fifo_enabled(&self) -> bool {
+ matches!(self.line_control.fifos_enabled(), registers::Mode::FIFO)
+ }
+
+ #[inline]
+ pub fn loopback_enabled(&self) -> bool {
+ self.control.enable_loopback()
+ }
+
+ #[inline]
+ pub fn fifo_depth(&self) -> usize {
+ // Note: FIFO depth is expected to be power-of-2
+ if self.fifo_enabled() {
+ return PL011_FIFO_DEPTH;
+ }
+ 1
+ }
+
+ pub fn put_fifo(&mut self, value: c_uint) {
+ let depth = self.fifo_depth();
+ assert!(depth > 0);
+ let slot = (self.read_pos + self.read_count) & (depth - 1);
+ self.read_fifo[slot] = value;
+ self.read_count += 1;
+ // s->flags &= ~PL011_FLAG_RXFE;
+ self.flags.set_receive_fifo_empty(false);
+ if self.read_count == depth {
+ //s->flags |= PL011_FLAG_RXFF;
+ self.flags.set_receive_fifo_full(true);
+ }
+
+ if self.read_count == self.read_trigger {
+ self.int_level |= registers::INT_RX;
+ self.update();
+ }
+ }
+
+ pub fn update(&self) {
+ let flags = self.int_level & self.int_enabled;
+ for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
+ // SAFETY: self.interrupts have been initialized in init().
+ unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
+ }
+ }
+}
+
+/// Which bits in the interrupt status matter for each outbound IRQ line ?
+pub const IRQMASK: [u32; 6] = [
+ /* combined IRQ */
+ Interrupt::E
+ | Interrupt::MS
+ | Interrupt::RT as u32
+ | Interrupt::TX as u32
+ | Interrupt::RX as u32,
+ Interrupt::RX as u32,
+ Interrupt::TX as u32,
+ Interrupt::RT as u32,
+ Interrupt::MS,
+ Interrupt::E,
+];
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_ref().can_receive().into()
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+///
+/// The buffer and size arguments must also be valid.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_receive(
+ opaque: *mut core::ffi::c_void,
+ buf: *const u8,
+ size: core::ffi::c_int,
+) {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ if state.as_ref().loopback_enabled() {
+ return;
+ }
+ if size > 0 {
+ debug_assert!(!buf.is_null());
+ state.as_mut().put_fifo(c_uint::from(buf.read_volatile()))
+ }
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_mut().event(event)
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer for `chr`.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_create(
+ addr: u64,
+ irq: qemu_irq,
+ chr: *mut Chardev,
+) -> *mut DeviceState {
+ unsafe {
+ let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
+ let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
+
+ qdev_prop_set_chr(dev, bindings::TYPE_CHARDEV.as_ptr(), chr);
+ sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
+ sysbus_mmio_map(sysbus, 0, addr);
+ sysbus_connect_irq(sysbus, 0, irq);
+ dev
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_init(obj: *mut Object) {
+ unsafe {
+ debug_assert!(!obj.is_null());
+ let mut state = NonNull::new_unchecked(obj.cast::<PL011State>());
+ state.as_mut().init();
+ }
+}
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
new file mode 100644
index 00000000000..b7ab31af02d
--- /dev/null
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -0,0 +1,70 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::ptr::NonNull;
+
+use qemu_api::{bindings::*, definitions::ObjectImpl};
+
+use crate::device::PL011State;
+
+#[used]
+pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
+ name: PL011State::TYPE_INFO.name,
+ unmigratable: true,
+ ..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() }
+};
+
+qemu_api::declare_properties! {
+ PL011_PROPERTIES,
+ qemu_api::define_property!(
+ c"chardev",
+ PL011State,
+ char_backend,
+ unsafe { &qdev_prop_chr },
+ CharBackend
+ ),
+ qemu_api::define_property!(
+ c"migrate-clk",
+ PL011State,
+ migrate_clock,
+ unsafe { &qdev_prop_bool },
+ bool
+ ),
+}
+
+qemu_api::device_class_init! {
+ pl011_class_init,
+ props => PL011_PROPERTIES,
+ realize_fn => Some(pl011_realize),
+ legacy_reset_fn => Some(pl011_reset),
+ vmsd => VMSTATE_PL011,
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
+ unsafe {
+ assert!(!dev.is_null());
+ let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
+ state.as_mut().realize();
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
+ unsafe {
+ assert!(!dev.is_null());
+ let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
+ state.as_mut().reset();
+ }
+}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
new file mode 100644
index 00000000000..2939ee50c99
--- /dev/null
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -0,0 +1,586 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// PL011 QEMU Device Model
+//
+// This library implements a device model for the PrimeCell® UART (PL011)
+// device in QEMU.
+//
+#![doc = include_str!("../README.md")]
+//! # Library crate
+//!
+//! See [`PL011State`](crate::device::PL011State) for the device model type and
+//! the [`registers`] module for register types.
+
+#![deny(
+ rustdoc::broken_intra_doc_links,
+ rustdoc::redundant_explicit_links,
+ clippy::correctness,
+ clippy::suspicious,
+ clippy::complexity,
+ clippy::perf,
+ clippy::cargo,
+ clippy::nursery,
+ clippy::style,
+ // restriction group
+ clippy::dbg_macro,
+ clippy::as_underscore,
+ clippy::assertions_on_result_states,
+ // pedantic group
+ clippy::doc_markdown,
+ clippy::borrow_as_ptr,
+ clippy::cast_lossless,
+ clippy::option_if_let_else,
+ clippy::missing_const_for_fn,
+ clippy::cognitive_complexity,
+ clippy::missing_safety_doc,
+ )]
+
+extern crate bilge;
+extern crate bilge_impl;
+extern crate qemu_api;
+
+pub mod device;
+pub mod device_class;
+pub mod memory_ops;
+
+pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
+
+/// Offset of each register from the base memory address of the device.
+///
+/// # Source
+/// ARM DDI 0183G, Table 3-1 p.3-3
+#[doc(alias = "offset")]
+#[allow(non_camel_case_types)]
+#[repr(u64)]
+#[derive(Debug)]
+pub enum RegisterOffset {
+ /// Data Register
+ ///
+ /// A write to this register initiates the actual data transmission
+ #[doc(alias = "UARTDR")]
+ DR = 0x000,
+ /// Receive Status Register or Error Clear Register
+ #[doc(alias = "UARTRSR")]
+ #[doc(alias = "UARTECR")]
+ RSR = 0x004,
+ /// Flag Register
+ ///
+ /// A read of this register shows if transmission is complete
+ #[doc(alias = "UARTFR")]
+ FR = 0x018,
+ /// Fractional Baud Rate Register
+ ///
+ /// responsible for baud rate speed
+ #[doc(alias = "UARTFBRD")]
+ FBRD = 0x028,
+ /// `IrDA` Low-Power Counter Register
+ #[doc(alias = "UARTILPR")]
+ ILPR = 0x020,
+ /// Integer Baud Rate Register
+ ///
+ /// Responsible for baud rate speed
+ #[doc(alias = "UARTIBRD")]
+ IBRD = 0x024,
+ /// line control register (data frame format)
+ #[doc(alias = "UARTLCR_H")]
+ LCR_H = 0x02C,
+ /// Toggle UART, transmission or reception
+ #[doc(alias = "UARTCR")]
+ CR = 0x030,
+ /// Interrupt FIFO Level Select Register
+ #[doc(alias = "UARTIFLS")]
+ FLS = 0x034,
+ /// Interrupt Mask Set/Clear Register
+ #[doc(alias = "UARTIMSC")]
+ IMSC = 0x038,
+ /// Raw Interrupt Status Register
+ #[doc(alias = "UARTRIS")]
+ RIS = 0x03C,
+ /// Masked Interrupt Status Register
+ #[doc(alias = "UARTMIS")]
+ MIS = 0x040,
+ /// Interrupt Clear Register
+ #[doc(alias = "UARTICR")]
+ ICR = 0x044,
+ /// DMA control Register
+ #[doc(alias = "UARTDMACR")]
+ DMACR = 0x048,
+ ///// Reserved, offsets `0x04C` to `0x07C`.
+ //Reserved = 0x04C,
+}
+
+impl core::convert::TryFrom<u64> for RegisterOffset {
+ type Error = u64;
+
+ fn try_from(value: u64) -> Result<Self, Self::Error> {
+ macro_rules! case {
+ ($($discriminant:ident),*$(,)*) => {
+ /* check that matching on all macro arguments compiles, which means we are not
+ * missing any enum value; if the type definition ever changes this will stop
+ * compiling.
+ */
+ const fn _assert_exhaustive(val: RegisterOffset) {
+ match val {
+ $(RegisterOffset::$discriminant => (),)*
+ }
+ }
+
+ match value {
+ $(x if x == Self::$discriminant as u64 => Ok(Self::$discriminant),)*
+ _ => Err(value),
+ }
+ }
+ }
+ case! { DR, RSR, FR, FBRD, ILPR, IBRD, LCR_H, CR, FLS, IMSC, RIS, MIS, ICR, DMACR }
+ }
+}
+
+pub mod registers {
+ //! Device registers exposed as typed structs which are backed by arbitrary
+ //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
+ //!
+ //! All PL011 registers are essentially 32-bit wide, but are typed here as
+ //! bitmaps with only the necessary width. That is, if a struct bitmap
+ //! in this module is for example 16 bits long, it should be conceived
+ //! as a 32-bit register where the unmentioned higher bits are always
+ //! unused thus treated as zero when read or written.
+ use bilge::prelude::*;
+
+ // TODO: FIFO Mode has different semantics
+ /// Data Register, `UARTDR`
+ ///
+ /// The `UARTDR` register is the data register.
+ ///
+ /// For words to be transmitted:
+ ///
+ /// - if the FIFOs are enabled, data written to this location is pushed onto
+ /// the transmit
+ /// FIFO
+ /// - if the FIFOs are not enabled, data is stored in the transmitter
+ /// holding register (the
+ /// bottom word of the transmit FIFO).
+ ///
+ /// The write operation initiates transmission from the UART. The data is
+ /// prefixed with a start bit, appended with the appropriate parity bit
+ /// (if parity is enabled), and a stop bit. The resultant word is then
+ /// transmitted.
+ ///
+ /// For received words:
+ ///
+ /// - if the FIFOs are enabled, the data byte and the 4-bit status (break,
+ /// frame, parity,
+ /// and overrun) is pushed onto the 12-bit wide receive FIFO
+ /// - if the FIFOs are not enabled, the data byte and status are stored in
+ /// the receiving
+ /// holding register (the bottom word of the receive FIFO).
+ ///
+ /// The received data byte is read by performing reads from the `UARTDR`
+ /// register along with the corresponding status information. The status
+ /// information can also be read by a read of the `UARTRSR/UARTECR`
+ /// register.
+ ///
+ /// # Note
+ ///
+ /// You must disable the UART before any of the control registers are
+ /// reprogrammed. When the UART is disabled in the middle of
+ /// transmission or reception, it completes the current character before
+ /// stopping.
+ ///
+ /// # Source
+ /// ARM DDI 0183G 3.3.1 Data Register, UARTDR
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ #[doc(alias = "UARTDR")]
+ pub struct Data {
+ _reserved: u4,
+ pub data: u8,
+ pub framing_error: bool,
+ pub parity_error: bool,
+ pub break_error: bool,
+ pub overrun_error: bool,
+ }
+
+ // TODO: FIFO Mode has different semantics
+ /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR`
+ ///
+ /// The UARTRSR/UARTECR register is the receive status register/error clear
+ /// register. Receive status can also be read from the `UARTRSR`
+ /// register. If the status is read from this register, then the status
+ /// information for break, framing and parity corresponds to the
+ /// data character read from the [Data register](Data), `UARTDR` prior to
+ /// reading the UARTRSR register. The status information for overrun is
+ /// set immediately when an overrun condition occurs.
+ ///
+ ///
+ /// # Note
+ /// The received data character must be read first from the [Data
+ /// Register](Data), `UARTDR` before reading the error status associated
+ /// with that data character from the `UARTRSR` register. This read
+ /// sequence cannot be reversed, because the `UARTRSR` register is
+ /// updated only when a read occurs from the `UARTDR` register. However,
+ /// the status information can also be obtained by reading the `UARTDR`
+ /// register
+ ///
+ /// # Source
+ /// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
+ /// UARTRSR/UARTECR
+ #[bitsize(8)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ pub struct ReceiveStatusErrorClear {
+ pub framing_error: bool,
+ pub parity_error: bool,
+ pub break_error: bool,
+ pub overrun_error: bool,
+ _reserved_unpredictable: u4,
+ }
+
+ impl ReceiveStatusErrorClear {
+ pub fn reset(&mut self) {
+ // All the bits are cleared to 0 on reset.
+ *self = 0.into();
+ }
+ }
+
+ impl Default for ReceiveStatusErrorClear {
+ fn default() -> Self {
+ 0.into()
+ }
+ }
+
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ /// Flag Register, `UARTFR`
+ #[doc(alias = "UARTFR")]
+ pub struct Flags {
+ /// CTS Clear to send. This bit is the complement of the UART clear to
+ /// send, `nUARTCTS`, modem status input. That is, the bit is 1
+ /// when `nUARTCTS` is LOW.
+ pub clear_to_send: bool,
+ /// DSR Data set ready. This bit is the complement of the UART data set
+ /// ready, `nUARTDSR`, modem status input. That is, the bit is 1 when
+ /// `nUARTDSR` is LOW.
+ pub data_set_ready: bool,
+ /// DCD Data carrier detect. This bit is the complement of the UART data
+ /// carrier detect, `nUARTDCD`, modem status input. That is, the bit is
+ /// 1 when `nUARTDCD` is LOW.
+ pub data_carrier_detect: bool,
+ /// BUSY UART busy. If this bit is set to 1, the UART is busy
+ /// transmitting data. This bit remains set until the complete
+ /// byte, including all the stop bits, has been sent from the
+ /// shift register. This bit is set as soon as the transmit FIFO
+ /// becomes non-empty, regardless of whether the UART is enabled
+ /// or not.
+ pub busy: bool,
+ /// RXFE Receive FIFO empty. The meaning of this bit depends on the
+ /// state of the FEN bit in the UARTLCR_H register. If the FIFO
+ /// is disabled, this bit is set when the receive holding
+ /// register is empty. If the FIFO is enabled, the RXFE bit is
+ /// set when the receive FIFO is empty.
+ pub receive_fifo_empty: bool,
+ /// TXFF Transmit FIFO full. The meaning of this bit depends on the
+ /// state of the FEN bit in the UARTLCR_H register. If the FIFO
+ /// is disabled, this bit is set when the transmit holding
+ /// register is full. If the FIFO is enabled, the TXFF bit is
+ /// set when the transmit FIFO is full.
+ pub transmit_fifo_full: bool,
+ /// RXFF Receive FIFO full. The meaning of this bit depends on the state
+ /// of the FEN bit in the UARTLCR_H register. If the FIFO is
+ /// disabled, this bit is set when the receive holding register
+ /// is full. If the FIFO is enabled, the RXFF bit is set when
+ /// the receive FIFO is full.
+ pub receive_fifo_full: bool,
+ /// Transmit FIFO empty. The meaning of this bit depends on the state of
+ /// the FEN bit in the [Line Control register](LineControl),
+ /// `UARTLCR_H`. If the FIFO is disabled, this bit is set when the
+ /// transmit holding register is empty. If the FIFO is enabled,
+ /// the TXFE bit is set when the transmit FIFO is empty. This
+ /// bit does not indicate if there is data in the transmit shift
+ /// register.
+ pub transmit_fifo_empty: bool,
+ /// `RI`, is `true` when `nUARTRI` is `LOW`.
+ pub ring_indicator: bool,
+ _reserved_zero_no_modify: u7,
+ }
+
+ impl Flags {
+ pub fn reset(&mut self) {
+ // After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1
+ self.set_receive_fifo_full(false);
+ self.set_transmit_fifo_full(false);
+ self.set_busy(false);
+ self.set_receive_fifo_empty(true);
+ self.set_transmit_fifo_empty(true);
+ }
+ }
+
+ impl Default for Flags {
+ fn default() -> Self {
+ let mut ret: Self = 0.into();
+ ret.reset();
+ ret
+ }
+ }
+
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ /// Line Control Register, `UARTLCR_H`
+ #[doc(alias = "UARTLCR_H")]
+ pub struct LineControl {
+ /// 15:8 - Reserved, do not modify, read as zero.
+ _reserved_zero_no_modify: u8,
+ /// 7 SPS Stick parity select.
+ /// 0 = stick parity is disabled
+ /// 1 = either:
+ /// • if the EPS bit is 0 then the parity bit is transmitted and checked
+ /// as a 1 • if the EPS bit is 1 then the parity bit is
+ /// transmitted and checked as a 0. This bit has no effect when
+ /// the PEN bit disables parity checking and generation. See Table 3-11
+ /// on page 3-14 for the parity truth table.
+ pub sticky_parity: bool,
+ /// WLEN Word length. These bits indicate the number of data bits
+ /// transmitted or received in a frame as follows: b11 = 8 bits
+ /// b10 = 7 bits
+ /// b01 = 6 bits
+ /// b00 = 5 bits.
+ pub word_length: WordLength,
+ /// FEN Enable FIFOs:
+ /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
+ /// 1-byte-deep holding registers 1 = transmit and receive FIFO
+ /// buffers are enabled (FIFO mode).
+ pub fifos_enabled: Mode,
+ /// 3 STP2 Two stop bits select. If this bit is set to 1, two stop bits
+ /// are transmitted at the end of the frame. The receive
+ /// logic does not check for two stop bits being received.
+ pub two_stops_bits: bool,
+ /// EPS Even parity select. Controls the type of parity the UART uses
+ /// during transmission and reception:
+ /// - 0 = odd parity. The UART generates or checks for an odd number of
+ /// 1s in the data and parity bits.
+ /// - 1 = even parity. The UART generates or checks for an even number
+ /// of 1s in the data and parity bits.
+ /// This bit has no effect when the `PEN` bit disables parity checking
+ /// and generation. See Table 3-11 on page 3-14 for the parity
+ /// truth table.
+ pub parity: Parity,
+ /// 1 PEN Parity enable:
+ ///
+ /// - 0 = parity is disabled and no parity bit added to the data frame
+ /// - 1 = parity checking and generation is enabled.
+ ///
+ /// See Table 3-11 on page 3-14 for the parity truth table.
+ pub parity_enabled: bool,
+ /// BRK Send break.
+ ///
+ /// If this bit is set to `1`, a low-level is continually output on the
+ /// `UARTTXD` output, after completing transmission of the
+ /// current character. For the proper execution of the break command,
+ /// the software must set this bit for at least two complete
+ /// frames. For normal use, this bit must be cleared to `0`.
+ pub send_break: bool,
+ }
+
+ impl LineControl {
+ pub fn reset(&mut self) {
+ // All the bits are cleared to 0 when reset.
+ *self = 0.into();
+ }
+ }
+
+ impl Default for LineControl {
+ fn default() -> Self {
+ 0.into()
+ }
+ }
+
+ #[bitsize(1)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `EPS` "Even parity select", field of [Line Control
+ /// register](LineControl).
+ pub enum Parity {
+ /// - 0 = odd parity. The UART generates or checks for an odd number of
+ /// 1s in the data and parity bits.
+ Odd = 0,
+ /// - 1 = even parity. The UART generates or checks for an even number
+ /// of 1s in the data and parity bits.
+ Even = 1,
+ }
+
+ #[bitsize(1)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `FEN` "Enable FIFOs" or Device mode, field of [Line Control
+ /// register](LineControl).
+ pub enum Mode {
+ /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
+ /// 1-byte-deep holding registers
+ Character = 0,
+ /// 1 = transmit and receive FIFO buffers are enabled (FIFO mode).
+ FIFO = 1,
+ }
+
+ impl From<Mode> for bool {
+ fn from(val: Mode) -> Self {
+ matches!(val, Mode::FIFO)
+ }
+ }
+
+ #[bitsize(2)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `WLEN` Word length, field of [Line Control register](LineControl).
+ ///
+ /// These bits indicate the number of data bits transmitted or received in a
+ /// frame as follows:
+ pub enum WordLength {
+ /// b11 = 8 bits
+ _8Bits = 0b11,
+ /// b10 = 7 bits
+ _7Bits = 0b10,
+ /// b01 = 6 bits
+ _6Bits = 0b01,
+ /// b00 = 5 bits.
+ _5Bits = 0b00,
+ }
+
+ /// Control Register, `UARTCR`
+ ///
+ /// The `UARTCR` register is the control register. All the bits are cleared
+ /// to `0` on reset except for bits `9` and `8` that are set to `1`.
+ ///
+ /// # Source
+ /// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
+ #[bitsize(16)]
+ #[doc(alias = "UARTCR")]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ pub struct Control {
+ /// `UARTEN` UART enable: 0 = UART is disabled. If the UART is disabled
+ /// in the middle of transmission or reception, it completes the current
+ /// character before stopping. 1 = the UART is enabled. Data
+ /// transmission and reception occurs for either UART signals or SIR
+ /// signals depending on the setting of the SIREN bit.
+ pub enable_uart: bool,
+ /// `SIREN` `SIR` enable: 0 = IrDA SIR ENDEC is disabled. `nSIROUT`
+ /// remains LOW (no light pulse generated), and signal transitions on
+ /// SIRIN have no effect. 1 = IrDA SIR ENDEC is enabled. Data is
+ /// transmitted and received on nSIROUT and SIRIN. UARTTXD remains HIGH,
+ /// in the marking state. Signal transitions on UARTRXD or modem status
+ /// inputs have no effect. This bit has no effect if the UARTEN bit
+ /// disables the UART.
+ pub enable_sir: bool,
+ /// `SIRLP` SIR low-power IrDA mode. This bit selects the IrDA encoding
+ /// mode. If this bit is cleared to 0, low-level bits are transmitted as
+ /// an active high pulse with a width of 3/ 16th of the bit period. If
+ /// this bit is set to 1, low-level bits are transmitted with a pulse
+ /// width that is 3 times the period of the IrLPBaud16 input signal,
+ /// regardless of the selected bit rate. Setting this bit uses less
+ /// power, but might reduce transmission distances.
+ pub sir_lowpower_irda_mode: u1,
+ /// Reserved, do not modify, read as zero.
+ _reserved_zero_no_modify: u4,
+ /// `LBE` Loopback enable. If this bit is set to 1 and the SIREN bit is
+ /// set to 1 and the SIRTEST bit in the Test Control register, UARTTCR
+ /// on page 4-5 is set to 1, then the nSIROUT path is inverted, and fed
+ /// through to the SIRIN path. The SIRTEST bit in the test register must
+ /// be set to 1 to override the normal half-duplex SIR operation. This
+ /// must be the requirement for accessing the test registers during
+ /// normal operation, and SIRTEST must be cleared to 0 when loopback
+ /// testing is finished. This feature reduces the amount of external
+ /// coupling required during system test. If this bit is set to 1, and
+ /// the SIRTEST bit is set to 0, the UARTTXD path is fed through to the
+ /// UARTRXD path. In either SIR mode or UART mode, when this bit is set,
+ /// the modem outputs are also fed through to the modem inputs. This bit
+ /// is cleared to 0 on reset, to disable loopback.
+ pub enable_loopback: bool,
+ /// `TXE` Transmit enable. If this bit is set to 1, the transmit section
+ /// of the UART is enabled. Data transmission occurs for either UART
+ /// signals, or SIR signals depending on the setting of the SIREN bit.
+ /// When the UART is disabled in the middle of transmission, it
+ /// completes the current character before stopping.
+ pub enable_transmit: bool,
+ /// `RXE` Receive enable. If this bit is set to 1, the receive section
+ /// of the UART is enabled. Data reception occurs for either UART
+ /// signals or SIR signals depending on the setting of the SIREN bit.
+ /// When the UART is disabled in the middle of reception, it completes
+ /// the current character before stopping.
+ pub enable_receive: bool,
+ /// `DTR` Data transmit ready. This bit is the complement of the UART
+ /// data transmit ready, `nUARTDTR`, modem status output. That is, when
+ /// the bit is programmed to a 1 then `nUARTDTR` is LOW.
+ pub data_transmit_ready: bool,
+ /// `RTS` Request to send. This bit is the complement of the UART
+ /// request to send, `nUARTRTS`, modem status output. That is, when the
+ /// bit is programmed to a 1 then `nUARTRTS` is LOW.
+ pub request_to_send: bool,
+ /// `Out1` This bit is the complement of the UART Out1 (`nUARTOut1`)
+ /// modem status output. That is, when the bit is programmed to a 1 the
+ /// output is 0. For DTE this can be used as Data Carrier Detect (DCD).
+ pub out_1: bool,
+ /// `Out2` This bit is the complement of the UART Out2 (`nUARTOut2`)
+ /// modem status output. That is, when the bit is programmed to a 1, the
+ /// output is 0. For DTE this can be used as Ring Indicator (RI).
+ pub out_2: bool,
+ /// `RTSEn` RTS hardware flow control enable. If this bit is set to 1,
+ /// RTS hardware flow control is enabled. Data is only requested when
+ /// there is space in the receive FIFO for it to be received.
+ pub rts_hardware_flow_control_enable: bool,
+ /// `CTSEn` CTS hardware flow control enable. If this bit is set to 1,
+ /// CTS hardware flow control is enabled. Data is only transmitted when
+ /// the `nUARTCTS` signal is asserted.
+ pub cts_hardware_flow_control_enable: bool,
+ }
+
+ impl Control {
+ pub fn reset(&mut self) {
+ *self = 0.into();
+ self.set_enable_receive(true);
+ self.set_enable_transmit(true);
+ }
+ }
+
+ impl Default for Control {
+ fn default() -> Self {
+ let mut ret: Self = 0.into();
+ ret.reset();
+ ret
+ }
+ }
+
+ /// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
+ pub const INT_OE: u32 = 1 << 10;
+ pub const INT_BE: u32 = 1 << 9;
+ pub const INT_PE: u32 = 1 << 8;
+ pub const INT_FE: u32 = 1 << 7;
+ pub const INT_RT: u32 = 1 << 6;
+ pub const INT_TX: u32 = 1 << 5;
+ pub const INT_RX: u32 = 1 << 4;
+ pub const INT_DSR: u32 = 1 << 3;
+ pub const INT_DCD: u32 = 1 << 2;
+ pub const INT_CTS: u32 = 1 << 1;
+ pub const INT_RI: u32 = 1 << 0;
+ pub const INT_E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
+ pub const INT_MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
+
+ #[repr(u32)]
+ pub enum Interrupt {
+ OE = 1 << 10,
+ BE = 1 << 9,
+ PE = 1 << 8,
+ FE = 1 << 7,
+ RT = 1 << 6,
+ TX = 1 << 5,
+ RX = 1 << 4,
+ DSR = 1 << 3,
+ DCD = 1 << 2,
+ CTS = 1 << 1,
+ RI = 1 << 0,
+ }
+
+ impl Interrupt {
+ pub const E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
+ pub const MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
+ }
+}
+
+// TODO: You must disable the UART before any of the control registers are
+// reprogrammed. When the UART is disabled in the middle of transmission or
+// reception, it completes the current character before stopping
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
new file mode 100644
index 00000000000..8d066ebf6d0
--- /dev/null
+++ b/rust/hw/char/pl011/src/memory_ops.rs
@@ -0,0 +1,59 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::{mem::MaybeUninit, ptr::NonNull};
+
+use qemu_api::bindings::*;
+
+use crate::device::PL011State;
+
+pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps {
+ read: Some(pl011_read),
+ write: Some(pl011_write),
+ read_with_attrs: None,
+ write_with_attrs: None,
+ endianness: device_endian::DEVICE_NATIVE_ENDIAN,
+ valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() },
+ impl_: MemoryRegionOps__bindgen_ty_2 {
+ min_access_size: 4,
+ max_access_size: 4,
+ ..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() }
+ },
+};
+
+#[no_mangle]
+unsafe extern "C" fn pl011_read(
+ opaque: *mut core::ffi::c_void,
+ addr: hwaddr,
+ size: core::ffi::c_uint,
+) -> u64 {
+ assert!(!opaque.is_null());
+ let mut state = unsafe { NonNull::new_unchecked(opaque.cast::<PL011State>()) };
+ let val = unsafe { state.as_mut().read(addr, size) };
+ match val {
+ std::ops::ControlFlow::Break(val) => val,
+ std::ops::ControlFlow::Continue(val) => {
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ let cb_ptr = unsafe { core::ptr::addr_of_mut!(state.as_mut().char_backend) };
+ unsafe { qemu_chr_fe_accept_input(cb_ptr) };
+
+ val
+ }
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn pl011_write(
+ opaque: *mut core::ffi::c_void,
+ addr: hwaddr,
+ data: u64,
+ _size: core::ffi::c_uint,
+) {
+ unsafe {
+ assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_mut().write(addr, data)
+ }
+}
diff --git a/rust/hw/meson.build b/rust/hw/meson.build
new file mode 100644
index 00000000000..860196645e7
--- /dev/null
+++ b/rust/hw/meson.build
@@ -0,0 +1 @@
+subdir('char')
diff --git a/rust/meson.build b/rust/meson.build
index 7a32b1b1950..def77389cdd 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -1,2 +1,4 @@
subdir('qemu-api-macros')
subdir('qemu-api')
+
+subdir('hw')
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 62a2cf45d28..30677c3ec90 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -27,7 +27,9 @@ 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 proc-macro2-1-rs quote-1-rs
+ berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
+ bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
+ proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
syn-2-rs unicode-ident-1-rs"
sub_deinit=""
diff --git a/scripts/make-release b/scripts/make-release
index cf7d694ef73..8dc939124c4 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -18,7 +18,9 @@ fi
# Only include wraps that are invoked with subproject()
SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
- berkeley-testfloat-3 proc-macro2-1-rs quote-1-rs
+ berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
+ bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
+ proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
syn-2-rs unicode-ident-1-rs"
src="$1"
diff --git a/scripts/rust/rust_root_crate.sh b/scripts/rust/rust_root_crate.sh
new file mode 100755
index 00000000000..975bddf7f1a
--- /dev/null
+++ b/scripts/rust/rust_root_crate.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -eu
+
+cat <<EOF
+// @generated
+// This file is autogenerated by scripts/rust_root_crate.sh
+
+EOF
+
+for crate in $*; do
+ echo "extern crate $crate;"
+done
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index b6888182ca4..50f173f90db 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -6,6 +6,13 @@
/keycodemapdb
/libvfio-user
/slirp
+/arbitrary-int-1.2.7
+/bilge-0.2.0
+/bilge-impl-0.2.0
+/either-1.12.0
+/itertools-0.11.0
+/proc-macro-error-1.0.4
+/proc-macro-error-attr-1.0.4
/proc-macro2-1.0.84
/quote-1.0.36
/syn-2.0.66
diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap
new file mode 100644
index 00000000000..e580538a877
--- /dev/null
+++ b/subprojects/arbitrary-int-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = arbitrary-int-1.2.7
+source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download
+source_filename = arbitrary-int-1.2.7.tar.gz
+source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d
+#method = cargo
+patch_directory = arbitrary-int-1-rs
diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap
new file mode 100644
index 00000000000..7a4339d2989
--- /dev/null
+++ b/subprojects/bilge-0.2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = bilge-0.2.0
+source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download
+source_filename = bilge-0.2.0.tar.gz
+source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57
+#method = cargo
+patch_directory = bilge-0.2-rs
diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap
new file mode 100644
index 00000000000..eefb10c36c2
--- /dev/null
+++ b/subprojects/bilge-impl-0.2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = bilge-impl-0.2.0
+source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download
+source_filename = bilge-impl-0.2.0.tar.gz
+source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8
+#method = cargo
+patch_directory = bilge-impl-0.2-rs
diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap
new file mode 100644
index 00000000000..6046712036c
--- /dev/null
+++ b/subprojects/either-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = either-1.12.0
+source_url = https://crates.io/api/v1/crates/either/1.12.0/download
+source_filename = either-1.12.0.tar.gz
+source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b
+#method = cargo
+patch_directory = either-1-rs
diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap
new file mode 100644
index 00000000000..66b05252cd5
--- /dev/null
+++ b/subprojects/itertools-0.11-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = itertools-0.11.0
+source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download
+source_filename = itertools-0.11.0.tar.gz
+source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57
+#method = cargo
+patch_directory = itertools-0.11-rs
diff --git a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
new file mode 100644
index 00000000000..34a189cbaec
--- /dev/null
+++ b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
@@ -0,0 +1,19 @@
+project('arbitrary-int-1-rs', 'rust',
+ version: '1.2.7',
+ license: 'MIT',
+ default_options: [])
+
+_arbitrary_int_rs = static_library(
+ 'arbitrary_int',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [],
+)
+
+arbitrary_int_dep = declare_dependency(
+ link_with: _arbitrary_int_rs,
+)
+
+meson.override_dependency('arbitrary-int-1-rs', arbitrary_int_dep)
diff --git a/subprojects/packagefiles/bilge-0.2-rs/meson.build b/subprojects/packagefiles/bilge-0.2-rs/meson.build
new file mode 100644
index 00000000000..a6ed4a8f0cd
--- /dev/null
+++ b/subprojects/packagefiles/bilge-0.2-rs/meson.build
@@ -0,0 +1,29 @@
+project(
+ 'bilge-0.2-rs',
+ 'rust',
+ version : '0.2.0',
+ license : 'MIT or Apache-2.0',
+)
+
+subproject('arbitrary-int-1-rs', required: true)
+subproject('bilge-impl-0.2-rs', required: true)
+
+arbitrary_int_dep = dependency('arbitrary-int-1-rs')
+bilge_impl_dep = dependency('bilge-impl-0.2-rs')
+
+lib = static_library(
+ 'bilge',
+ 'src/lib.rs',
+ override_options : ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi : 'rust',
+ dependencies: [
+ arbitrary_int_dep,
+ bilge_impl_dep,
+ ],
+)
+
+bilge_dep = declare_dependency(
+ link_with : [lib],
+)
+
+meson.override_dependency('bilge-0.2-rs', bilge_dep)
diff --git a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
new file mode 100644
index 00000000000..80243c7024d
--- /dev/null
+++ b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
@@ -0,0 +1,45 @@
+project('bilge-impl-0.2-rs', 'rust',
+ version: '0.2.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('itertools-0.11-rs', required: true)
+subproject('proc-macro-error-attr-1-rs', required: true)
+subproject('proc-macro-error-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+subproject('syn-2-rs', required: true)
+subproject('proc-macro2-1-rs', required: true)
+
+itertools_dep = dependency('itertools-0.11-rs', native: true)
+proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
+proc_macro_error_dep = dependency('proc-macro-error-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+
+rust = import('rust')
+
+_bilge_impl_rs = rust.proc_macro(
+ 'bilge_impl',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"',
+ ],
+ dependencies: [
+ itertools_dep,
+ proc_macro_error_attr_dep,
+ proc_macro_error_dep,
+ quote_dep,
+ syn_dep,
+ proc_macro2_dep,
+ ],
+)
+
+bilge_impl_dep = declare_dependency(
+ link_with: _bilge_impl_rs,
+)
+
+meson.override_dependency('bilge-impl-0.2-rs', bilge_impl_dep)
diff --git a/subprojects/packagefiles/either-1-rs/meson.build b/subprojects/packagefiles/either-1-rs/meson.build
new file mode 100644
index 00000000000..a5842eb3a6a
--- /dev/null
+++ b/subprojects/packagefiles/either-1-rs/meson.build
@@ -0,0 +1,24 @@
+project('either-1-rs', 'rust',
+ version: '1.12.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+_either_rs = static_library(
+ 'either',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="use_std"',
+ '--cfg', 'feature="use_alloc"',
+ ],
+ dependencies: [],
+ native: true,
+)
+
+either_dep = declare_dependency(
+ link_with: _either_rs,
+)
+
+meson.override_dependency('either-1-rs', either_dep, native: true)
diff --git a/subprojects/packagefiles/itertools-0.11-rs/meson.build b/subprojects/packagefiles/itertools-0.11-rs/meson.build
new file mode 100644
index 00000000000..13d2d27019d
--- /dev/null
+++ b/subprojects/packagefiles/itertools-0.11-rs/meson.build
@@ -0,0 +1,30 @@
+project('itertools-0.11-rs', 'rust',
+ version: '0.11.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('either-1-rs', required: true)
+
+either_dep = dependency('either-1-rs', native: true)
+
+_itertools_rs = static_library(
+ 'itertools',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="use_std"',
+ '--cfg', 'feature="use_alloc"',
+ ],
+ dependencies: [
+ either_dep,
+ ],
+ native: true,
+)
+
+itertools_dep = declare_dependency(
+ link_with: _itertools_rs,
+)
+
+meson.override_dependency('itertools-0.11-rs', itertools_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
new file mode 100644
index 00000000000..38ea7b89d39
--- /dev/null
+++ b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
@@ -0,0 +1,40 @@
+project('proc-macro-error-1-rs', 'rust',
+ version: '1.0.4',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro-error-attr-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+subproject('syn-2-rs', required: true)
+subproject('proc-macro2-1-rs', required: true)
+
+proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+
+_proc_macro_error_rs = static_library(
+ 'proc_macro_error',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"',
+ '-A', 'non_fmt_panics'
+ ],
+ dependencies: [
+ proc_macro_error_attr_dep,
+ proc_macro2_dep,
+ quote_dep,
+ syn_dep,
+ ],
+ native: true,
+)
+
+proc_macro_error_dep = declare_dependency(
+ link_with: _proc_macro_error_rs,
+)
+
+meson.override_dependency('proc-macro-error-1-rs', proc_macro_error_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
new file mode 100644
index 00000000000..d900c54cfd1
--- /dev/null
+++ b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
@@ -0,0 +1,32 @@
+project('proc-macro-error-attr-1-rs', 'rust',
+ version: '1.12.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro2-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+
+rust = import('rust')
+_proc_macro_error_attr_rs = rust.proc_macro(
+ 'proc_macro_error_attr',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"'
+ ],
+ dependencies: [
+ proc_macro2_dep,
+ quote_dep,
+ ],
+)
+
+proc_macro_error_attr_dep = declare_dependency(
+ link_with: _proc_macro_error_attr_rs,
+)
+
+meson.override_dependency('proc-macro-error-attr-1-rs', proc_macro_error_attr_dep, native: true)
diff --git a/subprojects/packagefiles/unicode-ident-1-rs/meson.build b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
new file mode 100644
index 00000000000..54f23768545
--- /dev/null
+++ b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
@@ -0,0 +1,20 @@
+project('unicode-ident-1-rs', 'rust',
+ version: '1.0.12',
+ license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
+ default_options: [])
+
+_unicode_ident_rs = static_library(
+ 'unicode_ident',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [],
+ native: true,
+)
+
+unicode_ident_dep = declare_dependency(
+ link_with: _unicode_ident_rs,
+)
+
+meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap
new file mode 100644
index 00000000000..b7db03b06a0
--- /dev/null
+++ b/subprojects/proc-macro-error-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = proc-macro-error-1.0.4
+source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download
+source_filename = proc-macro-error-1.0.4.tar.gz
+source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c
+#method = cargo
+patch_directory = proc-macro-error-1-rs
diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap
new file mode 100644
index 00000000000..d13d8a239ac
--- /dev/null
+++ b/subprojects/proc-macro-error-attr-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = proc-macro-error-attr-1.0.4
+source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download
+source_filename = proc-macro-error-attr-1.0.4.tar.gz
+source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869
+#method = cargo
+patch_directory = proc-macro-error-attr-1-rs
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 05/40] meson: import rust module into a global variable
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (3 preceding siblings ...)
2024-11-04 17:26 ` [PULL 04/40] rust: add PL011 device model Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 06/40] meson: remove repeated search for rust_root_crate.sh Paolo Bonzini
` (35 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Tested-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 3 ++-
rust/qemu-api-macros/meson.build | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/meson.build b/meson.build
index f7d45175212..dd6193c4c37 100644
--- a/meson.build
+++ b/meson.build
@@ -15,6 +15,7 @@ meson.add_postconf_script(find_program('scripts/symlink-install-tree.py'))
not_found = dependency('', required: false)
keyval = import('keyval')
+rust = import('rust')
ss = import('sourceset')
fs = import('fs')
@@ -3977,7 +3978,7 @@ if have_rust and have_system
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
- bindings_rs = import('rust').bindgen(
+ bindings_rs = rust.bindgen(
input: 'rust/wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.rs',
diff --git a/rust/qemu-api-macros/meson.build b/rust/qemu-api-macros/meson.build
index 517b9a4d2d5..24325dea5c2 100644
--- a/rust/qemu-api-macros/meson.build
+++ b/rust/qemu-api-macros/meson.build
@@ -2,7 +2,7 @@ quote_dep = dependency('quote-1-rs', native: true)
syn_dep = dependency('syn-2-rs', native: true)
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
-_qemu_api_macros_rs = import('rust').proc_macro(
+_qemu_api_macros_rs = rust.proc_macro(
'qemu_api_macros',
files('src/lib.rs'),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 06/40] meson: remove repeated search for rust_root_crate.sh
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (4 preceding siblings ...)
2024-11-04 17:26 ` [PULL 05/40] meson: import rust module into a global variable Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 07/40] meson: pass rustc_args when building all crates Paolo Bonzini
` (34 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Avoid repeated lines of the form
Program scripts/rust/rust_root_crate.sh found: YES (/home/pbonzini/work/upstream/qemu/scripts/rust/rust_root_crate.sh)
in the meson logs.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index dd6193c4c37..29a8df6d5f2 100644
--- a/meson.build
+++ b/meson.build
@@ -3991,6 +3991,7 @@ endif
feature_to_c = find_program('scripts/feature_to_c.py')
+rust_root_crate = find_program('scripts/rust/rust_root_crate.sh')
if host_os == 'darwin'
entitlement = find_program('scripts/entitlement.sh')
@@ -4092,7 +4093,7 @@ foreach target : target_dirs
if crates.length() > 0
rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
output: 'rust_' + target.underscorify() + '.rs',
- command: [find_program('scripts/rust/rust_root_crate.sh')] + crates,
+ command: [rust_root_crate, crates],
capture: true,
build_by_default: true,
build_always_stale: true)
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 07/40] meson: pass rustc_args when building all crates
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (5 preceding siblings ...)
2024-11-04 17:26 ` [PULL 06/40] meson: remove repeated search for rust_root_crate.sh Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 08/40] rust: do not always select X_PL011_RUST Paolo Bonzini
` (33 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
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>
---
meson.build | 20 +++++++++++++-------
rust/qemu-api/meson.build | 2 +-
rust/qemu-api/src/device_class.rs | 10 ++++++----
3 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/meson.build b/meson.build
index 29a8df6d5f2..7d06d2fe74e 100644
--- a/meson.build
+++ b/meson.build
@@ -3331,6 +3331,19 @@ endif
genh += configure_file(output: 'config-host.h', configuration: config_host_data)
+if have_rust and have_system
+ rustc_args = run_command(
+ find_program('scripts/rust/rustc_args.py'),
+ '--config-headers', meson.project_build_root() / 'config-host.h',
+ capture : true,
+ check: true).stdout().strip().split()
+
+ # Prohibit code that is forbidden in Rust 2024
+ rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
+ add_project_arguments(rustc_args, native: false, language: 'rust')
+ add_project_arguments(rustc_args, native: true, language: 'rust')
+endif
+
hxtool = find_program('scripts/hxtool')
shaderinclude = find_program('scripts/shaderinclude.py')
qapi_gen = find_program('scripts/qapi-gen.py')
@@ -3923,12 +3936,6 @@ common_all = static_library('common',
dependencies: common_ss.all_dependencies())
if have_rust and have_system
- rustc_args = run_command(
- find_program('scripts/rust/rustc_args.py'),
- '--config-headers', meson.project_build_root() / 'config-host.h',
- capture : true,
- check: true).stdout().strip().split()
- rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
bindgen_args = [
'--disable-header-comment',
'--raw-line', '// @generated',
@@ -4101,7 +4108,6 @@ foreach target : target_dirs
rlib_rs,
dependencies: target_rust.dependencies(),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_args: rustc_args,
rust_abi: 'c')
arch_deps += declare_dependency(link_whole: [rlib])
endif
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index c72d34b607d..42ea815fa5a 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -10,7 +10,7 @@ _qemu_api_rs = static_library(
),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
- rust_args: rustc_args + [
+ rust_args: [
'--cfg', 'MESON',
# '--cfg', 'feature="allocator"',
],
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index 1ea95beb78d..b6b68cf9ce2 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -16,10 +16,12 @@ macro_rules! device_class_init {
) {
let mut dc =
::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap();
- dc.as_mut().realize = $realize_fn;
- dc.as_mut().vmsd = &$vmsd;
- $crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn);
- $crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr());
+ unsafe {
+ dc.as_mut().realize = $realize_fn;
+ dc.as_mut().vmsd = &$vmsd;
+ $crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn);
+ $crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr());
+ }
}
};
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 08/40] rust: do not always select X_PL011_RUST
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (6 preceding siblings ...)
2024-11-04 17:26 ` [PULL 07/40] meson: pass rustc_args when building all crates Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 09/40] rust: do not use --no-size_t-is-usize Paolo Bonzini
` (32 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Right now the Rust pl011 device is included in all QEMU system
emulator binaries if --enable-rust is passed. This is not needed
since the board logic in hw/arm/Kconfig will pick it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/rust/hw/char/Kconfig b/rust/hw/char/Kconfig
index a1732a9e97f..5fe800c4806 100644
--- a/rust/hw/char/Kconfig
+++ b/rust/hw/char/Kconfig
@@ -1,3 +1,2 @@
config X_PL011_RUST
bool
- default y if HAVE_RUST
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 09/40] rust: do not use --no-size_t-is-usize
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (7 preceding siblings ...)
2024-11-04 17:26 ` [PULL 08/40] rust: do not always select X_PL011_RUST Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 10/40] rust: remove uses of #[no_mangle] Paolo Bonzini
` (31 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
This is not necessary and makes it harder to write code that is
portable between 32- and 64-bit systems: it adds extra casts even
though size_of, align_of or offset_of already return the right type.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 1 -
rust/qemu-api/src/definitions.rs | 6 +++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/meson.build b/meson.build
index 7d06d2fe74e..34328f7394c 100644
--- a/meson.build
+++ b/meson.build
@@ -3948,7 +3948,6 @@ if have_rust and have_system
'--no-doc-comments',
'--use-core',
'--with-derive-default',
- '--no-size_t-is-usize',
'--no-layout-tests',
'--no-prepend-enum-name',
'--allowlist-file', meson.project_source_root() + '/include/.*',
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
index 60bd3f8aaa6..0b681c593f2 100644
--- a/rust/qemu-api/src/definitions.rs
+++ b/rust/qemu-api/src/definitions.rs
@@ -81,13 +81,13 @@ macro_rules! type_info {
} else {
::core::ptr::null_mut()
},
- instance_size: ::core::mem::size_of::<$t>() as $crate::bindings::size_t,
- instance_align: ::core::mem::align_of::<$t>() as $crate::bindings::size_t,
+ instance_size: ::core::mem::size_of::<$t>(),
+ instance_align: ::core::mem::align_of::<$t>(),
instance_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_INIT,
instance_post_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_POST_INIT,
instance_finalize: <$t as $crate::definitions::ObjectImpl>::INSTANCE_FINALIZE,
abstract_: <$t as $crate::definitions::ObjectImpl>::ABSTRACT,
- class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>() as $crate::bindings::size_t,
+ class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>(),
class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_INIT,
class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_BASE_INIT,
class_data: ::core::ptr::null_mut(),
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 10/40] rust: remove uses of #[no_mangle]
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (8 preceding siblings ...)
2024-11-04 17:26 ` [PULL 09/40] rust: do not use --no-size_t-is-usize Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 11/40] rust: modernize link_section usage for ELF platforms Paolo Bonzini
` (30 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Mangled symbols do not cause any issue; disabling mangling is only useful if
C headers reference the Rust function, which is not the case here.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/pl011/src/device.rs | 4 ----
rust/hw/char/pl011/src/device_class.rs | 2 --
rust/hw/char/pl011/src/memory_ops.rs | 2 --
rust/qemu-api/src/definitions.rs | 1 -
rust/qemu-api/src/device_class.rs | 2 --
5 files changed, 11 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index c7193b41bee..0347a027c5f 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -514,7 +514,6 @@ pub fn update(&self) {
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-#[no_mangle]
pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
unsafe {
debug_assert!(!opaque.is_null());
@@ -530,7 +529,6 @@ pub fn update(&self) {
/// readable/writeable from one thread at any time.
///
/// The buffer and size arguments must also be valid.
-#[no_mangle]
pub unsafe extern "C" fn pl011_receive(
opaque: *mut core::ffi::c_void,
buf: *const u8,
@@ -554,7 +552,6 @@ pub fn update(&self) {
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-#[no_mangle]
pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
unsafe {
debug_assert!(!opaque.is_null());
@@ -589,7 +586,6 @@ pub fn update(&self) {
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-#[no_mangle]
pub unsafe extern "C" fn pl011_init(obj: *mut Object) {
unsafe {
debug_assert!(!obj.is_null());
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index b7ab31af02d..2ad80451e87 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -46,7 +46,6 @@
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-#[no_mangle]
pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
unsafe {
assert!(!dev.is_null());
@@ -60,7 +59,6 @@
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-#[no_mangle]
pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
unsafe {
assert!(!dev.is_null());
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
index 8d066ebf6d0..5a5320e66c3 100644
--- a/rust/hw/char/pl011/src/memory_ops.rs
+++ b/rust/hw/char/pl011/src/memory_ops.rs
@@ -22,7 +22,6 @@
},
};
-#[no_mangle]
unsafe extern "C" fn pl011_read(
opaque: *mut core::ffi::c_void,
addr: hwaddr,
@@ -44,7 +43,6 @@
}
}
-#[no_mangle]
unsafe extern "C" fn pl011_write(
opaque: *mut core::ffi::c_void,
addr: hwaddr,
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
index 0b681c593f2..49ac59af123 100644
--- a/rust/qemu-api/src/definitions.rs
+++ b/rust/qemu-api/src/definitions.rs
@@ -53,7 +53,6 @@ extern "C" fn __load() {
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
pub static LOAD_MODULE: extern "C" fn() = {
extern "C" fn __load() {
- #[no_mangle]
unsafe extern "C" fn $func() {
$body
}
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index b6b68cf9ce2..2219b9f73d0 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -9,7 +9,6 @@
#[macro_export]
macro_rules! device_class_init {
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
- #[no_mangle]
pub unsafe extern "C" fn $func(
klass: *mut $crate::bindings::ObjectClass,
_: *mut ::core::ffi::c_void,
@@ -103,7 +102,6 @@ const fn _calc_prop_len() -> usize {
]
}
- #[no_mangle]
pub static mut $ident: $crate::device_class::Properties<PROP_LEN> = $crate::device_class::Properties(::std::sync::OnceLock::new(), _make_properties);
};
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 11/40] rust: modernize link_section usage for ELF platforms
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (9 preceding siblings ...)
2024-11-04 17:26 ` [PULL 10/40] rust: remove uses of #[no_mangle] Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 12/40] rust: build integration test for the qemu_api crate Paolo Bonzini
` (29 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Some newer ABI implementations do not provide .ctors; and while
some linkers rewrite .ctors into .init_array, not all of them do.
Use the newer .init_array ABI, which works more reliably, and
apply it to all non-Apple, non-Windows platforms.
This is similar to how the ctor crate operates; without this change,
"#[derive(Object)]" does not work on Fedora 41.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api-macros/src/lib.rs | 7 +++++--
rust/qemu-api/src/definitions.rs | 14 ++++++++++----
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index 59aba592d9a..70e3f920460 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -16,8 +16,11 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
let expanded = quote! {
#[allow(non_upper_case_globals)]
#[used]
- #[cfg_attr(target_os = "linux", link_section = ".ctors")]
- #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(
+ not(any(target_vendor = "apple", target_os = "windows")),
+ link_section = ".init_array"
+ )]
+ #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
pub static #module_static: extern "C" fn() = {
extern "C" fn __register() {
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
index 49ac59af123..3323a665d92 100644
--- a/rust/qemu-api/src/definitions.rs
+++ b/rust/qemu-api/src/definitions.rs
@@ -31,8 +31,11 @@ pub trait Class {
macro_rules! module_init {
($func:expr, $type:expr) => {
#[used]
- #[cfg_attr(target_os = "linux", link_section = ".ctors")]
- #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(
+ not(any(target_vendor = "apple", target_os = "windows")),
+ link_section = ".init_array"
+ )]
+ #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
pub static LOAD_MODULE: extern "C" fn() = {
extern "C" fn __load() {
@@ -48,8 +51,11 @@ extern "C" fn __load() {
// NOTE: To have custom identifiers for the ctor func we need to either supply
// them directly as a macro argument or create them with a proc macro.
#[used]
- #[cfg_attr(target_os = "linux", link_section = ".ctors")]
- #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(
+ not(any(target_vendor = "apple", target_os = "windows")),
+ link_section = ".init_array"
+ )]
+ #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
pub static LOAD_MODULE: extern "C" fn() = {
extern "C" fn __load() {
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 12/40] rust: build integration test for the qemu_api crate
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (10 preceding siblings ...)
2024-11-04 17:26 ` [PULL 11/40] rust: modernize link_section usage for ELF platforms Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-12-19 9:53 ` Bernhard Beschow
2024-11-04 17:26 ` [PULL 13/40] rust: cleanup module_init!, use it from #[derive(Object)] Paolo Bonzini
` (28 subsequent siblings)
40 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
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>
---
meson.build | 10 ++++-
rust/qemu-api/meson.build | 26 ++++++++++--
rust/qemu-api/src/lib.rs | 3 --
rust/qemu-api/src/tests.rs | 49 ----------------------
rust/qemu-api/tests/tests.rs | 78 ++++++++++++++++++++++++++++++++++++
5 files changed, 110 insertions(+), 56 deletions(-)
delete mode 100644 rust/qemu-api/src/tests.rs
create mode 100644 rust/qemu-api/tests/tests.rs
diff --git a/meson.build b/meson.build
index 34328f7394c..d360120b233 100644
--- a/meson.build
+++ b/meson.build
@@ -3340,7 +3340,15 @@ if have_rust and have_system
# Prohibit code that is forbidden in Rust 2024
rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
- add_project_arguments(rustc_args, native: false, language: 'rust')
+
+ # Apart from procedural macros, our Rust executables will often link
+ # with C code, so include all the libraries that C code needs. This
+ # is safe; https://github.com/rust-lang/rust/pull/54675 says that
+ # passing -nodefaultlibs to the linker "was more ideological to
+ # start with than anything".
+ add_project_arguments(rustc_args + ['-C', 'default-linker-libraries'],
+ native: false, language: 'rust')
+
add_project_arguments(rustc_args, native: true, language: 'rust')
endif
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 42ea815fa5a..1fc36078027 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -14,11 +14,31 @@ _qemu_api_rs = static_library(
'--cfg', 'MESON',
# '--cfg', 'feature="allocator"',
],
- dependencies: [
- qemu_api_macros,
- ],
)
qemu_api = declare_dependency(
link_with: _qemu_api_rs,
+ dependencies: qemu_api_macros,
)
+
+# Rust executables do not support objects, so add an intermediate step.
+rust_qemu_api_objs = static_library(
+ 'rust_qemu_api_objs',
+ objects: [libqom.extract_all_objects(recursive: false),
+ libhwcore.extract_all_objects(recursive: false)])
+
+test('rust-qemu-api-integration',
+ executable(
+ 'rust-qemu-api-integration',
+ 'tests/tests.rs',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: ['--test'],
+ install: false,
+ dependencies: [qemu_api, qemu_api_macros],
+ link_whole: [rust_qemu_api_objs, libqemuutil]),
+ args: [
+ '--test',
+ '--format', 'pretty',
+ ],
+ protocol: 'rust',
+ suite: ['unit', 'rust'])
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index e72fb4b4bb1..6bc68076aae 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -30,9 +30,6 @@ unsafe impl Sync for bindings::VMStateDescription {}
pub mod definitions;
pub mod device_class;
-#[cfg(test)]
-mod tests;
-
use std::alloc::{GlobalAlloc, Layout};
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
diff --git a/rust/qemu-api/src/tests.rs b/rust/qemu-api/src/tests.rs
deleted file mode 100644
index df54edbd4e2..00000000000
--- a/rust/qemu-api/src/tests.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2024, Linaro Limited
-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-use crate::{
- bindings::*, declare_properties, define_property, device_class_init, vm_state_description,
-};
-
-#[test]
-fn test_device_decl_macros() {
- // Test that macros can compile.
- vm_state_description! {
- VMSTATE,
- name: c"name",
- unmigratable: true,
- }
-
- #[repr(C)]
- pub struct DummyState {
- pub char_backend: CharBackend,
- pub migrate_clock: bool,
- }
-
- declare_properties! {
- DUMMY_PROPERTIES,
- define_property!(
- c"chardev",
- DummyState,
- char_backend,
- unsafe { &qdev_prop_chr },
- CharBackend
- ),
- define_property!(
- c"migrate-clk",
- DummyState,
- migrate_clock,
- unsafe { &qdev_prop_bool },
- bool
- ),
- }
-
- device_class_init! {
- dummy_class_init,
- props => DUMMY_PROPERTIES,
- realize_fn => None,
- reset_fn => None,
- vmsd => VMSTATE,
- }
-}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
new file mode 100644
index 00000000000..aa1e0568c69
--- /dev/null
+++ b/rust/qemu-api/tests/tests.rs
@@ -0,0 +1,78 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::ffi::CStr;
+
+use qemu_api::{
+ bindings::*,
+ declare_properties, define_property,
+ definitions::{Class, ObjectImpl},
+ device_class_init, vm_state_description,
+};
+
+#[test]
+fn test_device_decl_macros() {
+ // Test that macros can compile.
+ vm_state_description! {
+ VMSTATE,
+ name: c"name",
+ unmigratable: true,
+ }
+
+ #[repr(C)]
+ #[derive(qemu_api_macros::Object)]
+ pub struct DummyState {
+ pub _parent: DeviceState,
+ pub migrate_clock: bool,
+ }
+
+ #[repr(C)]
+ pub struct DummyClass {
+ pub _parent: DeviceClass,
+ }
+
+ declare_properties! {
+ DUMMY_PROPERTIES,
+ define_property!(
+ c"migrate-clk",
+ DummyState,
+ migrate_clock,
+ unsafe { &qdev_prop_bool },
+ bool
+ ),
+ }
+
+ device_class_init! {
+ dummy_class_init,
+ props => DUMMY_PROPERTIES,
+ realize_fn => None,
+ legacy_reset_fn => None,
+ vmsd => VMSTATE,
+ }
+
+ impl ObjectImpl for DummyState {
+ type Class = DummyClass;
+ const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
+ const TYPE_NAME: &'static CStr = c"dummy";
+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_DEVICE);
+ const ABSTRACT: bool = false;
+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ }
+
+ impl Class for DummyClass {
+ const CLASS_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = Some(dummy_class_init);
+ const CLASS_BASE_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = None;
+ }
+
+ unsafe {
+ module_call_init(module_init_type::MODULE_INIT_QOM);
+ object_unref(object_new(DummyState::TYPE_NAME.as_ptr()) as *mut _);
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 13/40] rust: cleanup module_init!, use it from #[derive(Object)]
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (11 preceding siblings ...)
2024-11-04 17:26 ` [PULL 12/40] rust: build integration test for the qemu_api crate Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 14/40] rust: clean up define_property macro Paolo Bonzini
` (27 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Remove the duplicate code by using the module_init! macro; at the same time,
simplify how module_init! is used, by taking inspiration from the implementation
of #[derive(Object)].
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api-macros/src/lib.rs | 33 +++-------------
rust/qemu-api/src/definitions.rs | 65 +++++++++++++-------------------
2 files changed, 32 insertions(+), 66 deletions(-)
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index 70e3f920460..a4bc5d01ee8 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -3,43 +3,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use proc_macro::TokenStream;
-use quote::{format_ident, quote};
+use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Object)]
pub fn derive_object(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
-
let name = input.ident;
- let module_static = format_ident!("__{}_LOAD_MODULE", name);
let expanded = quote! {
- #[allow(non_upper_case_globals)]
- #[used]
- #[cfg_attr(
- not(any(target_vendor = "apple", target_os = "windows")),
- link_section = ".init_array"
- )]
- #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
- #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
- pub static #module_static: extern "C" fn() = {
- extern "C" fn __register() {
- unsafe {
- ::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::definitions::ObjectImpl>::TYPE_INFO);
- }
+ ::qemu_api::module_init! {
+ MODULE_INIT_QOM => unsafe {
+ ::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::definitions::ObjectImpl>::TYPE_INFO);
}
-
- extern "C" fn __load() {
- unsafe {
- ::qemu_api::bindings::register_module_init(
- Some(__register),
- ::qemu_api::bindings::module_init_type::MODULE_INIT_QOM
- );
- }
- }
-
- __load
- };
+ }
};
TokenStream::from(expanded)
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
index 3323a665d92..064afe60549 100644
--- a/rust/qemu-api/src/definitions.rs
+++ b/rust/qemu-api/src/definitions.rs
@@ -29,51 +29,40 @@ pub trait Class {
#[macro_export]
macro_rules! module_init {
- ($func:expr, $type:expr) => {
- #[used]
- #[cfg_attr(
- not(any(target_vendor = "apple", target_os = "windows")),
- link_section = ".init_array"
- )]
- #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
- #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
- pub static LOAD_MODULE: extern "C" fn() = {
- extern "C" fn __load() {
- unsafe {
- $crate::bindings::register_module_init(Some($func), $type);
- }
- }
-
- __load
- };
- };
- (qom: $func:ident => $body:block) => {
- // NOTE: To have custom identifiers for the ctor func we need to either supply
- // them directly as a macro argument or create them with a proc macro.
- #[used]
- #[cfg_attr(
- not(any(target_vendor = "apple", target_os = "windows")),
- link_section = ".init_array"
- )]
- #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
- #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
- pub static LOAD_MODULE: extern "C" fn() = {
- extern "C" fn __load() {
- unsafe extern "C" fn $func() {
+ ($type:ident => $body:block) => {
+ const _: () = {
+ #[used]
+ #[cfg_attr(
+ not(any(target_vendor = "apple", target_os = "windows")),
+ link_section = ".init_array"
+ )]
+ #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
+ pub static LOAD_MODULE: extern "C" fn() = {
+ extern "C" fn init_fn() {
$body
}
- unsafe {
- $crate::bindings::register_module_init(
- Some($func),
- $crate::bindings::module_init_type::MODULE_INIT_QOM,
- );
+ extern "C" fn ctor_fn() {
+ unsafe {
+ $crate::bindings::register_module_init(
+ Some(init_fn),
+ $crate::bindings::module_init_type::$type,
+ );
+ }
}
- }
- __load
+ ctor_fn
+ };
};
};
+
+ // shortcut because it's quite common that $body needs unsafe {}
+ ($type:ident => unsafe $body:block) => {
+ $crate::module_init! {
+ $type => { unsafe { $body } }
+ }
+ };
}
#[macro_export]
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 14/40] rust: clean up define_property macro
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (12 preceding siblings ...)
2024-11-04 17:26 ` [PULL 13/40] rust: cleanup module_init!, use it from #[derive(Object)] Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 15/40] rust: make properties array immutable Paolo Bonzini
` (26 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Use the "struct update" syntax to initialize most of the fields to zero,
and simplify the handmade type-checking of $name.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/src/device_class.rs | 31 +++++++------------------------
1 file changed, 7 insertions(+), 24 deletions(-)
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index 2219b9f73d0..aab60484096 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -29,44 +29,27 @@ macro_rules! device_class_init {
macro_rules! define_property {
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
$crate::bindings::Property {
- name: {
- #[used]
- static _TEMP: &::core::ffi::CStr = $name;
- _TEMP.as_ptr()
- },
+ // use associated function syntax for type checking
+ name: ::core::ffi::CStr::as_ptr($name),
info: $prop,
offset: ::core::mem::offset_of!($state, $field)
.try_into()
.expect("Could not fit offset value to type"),
- bitnr: 0,
- bitmask: 0,
set_default: true,
- defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval.into() },
- arrayoffset: 0,
- arrayinfo: ::core::ptr::null(),
- arrayfieldsize: 0,
- link_type: ::core::ptr::null(),
+ defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
+ ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
}
};
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
$crate::bindings::Property {
- name: {
- #[used]
- static _TEMP: &::core::ffi::CStr = $name;
- _TEMP.as_ptr()
- },
+ // use associated function syntax for type checking
+ name: ::core::ffi::CStr::as_ptr($name),
info: $prop,
offset: ::core::mem::offset_of!($state, $field)
.try_into()
.expect("Could not fit offset value to type"),
- bitnr: 0,
- bitmask: 0,
set_default: false,
- defval: $crate::bindings::Property__bindgen_ty_1 { i: 0 },
- arrayoffset: 0,
- arrayinfo: ::core::ptr::null(),
- arrayfieldsize: 0,
- link_type: ::core::ptr::null(),
+ ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
}
};
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 15/40] rust: make properties array immutable
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (13 preceding siblings ...)
2024-11-04 17:26 ` [PULL 14/40] rust: clean up define_property macro Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 16/40] rust: provide safe wrapper for MaybeUninit::zeroed() Paolo Bonzini
` (25 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Now that device_class_set_props() takes a const pointer, the only part of
"define_property!" that needs to be non-const is the call to try_into().
This in turn will only break if offset_of returns a value with the most
significant bit set (i.e. a struct size that is >=2^31 or >= 2^63,
respectively on 32- and 64-bit system), which is impossible.
Just use a cast and clean everything up to remove the run-time
initialization. This also removes a use of OnceLock, which was only
stabilized in 1.70.0.
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/src/device_class.rs | 42 ++++++-------------------------
1 file changed, 8 insertions(+), 34 deletions(-)
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index aab60484096..4b14cb3ffd6 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -2,10 +2,6 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::sync::OnceLock;
-
-use crate::bindings::Property;
-
#[macro_export]
macro_rules! device_class_init {
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
@@ -19,7 +15,7 @@ macro_rules! device_class_init {
dc.as_mut().realize = $realize_fn;
dc.as_mut().vmsd = &$vmsd;
$crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn);
- $crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr());
+ $crate::bindings::device_class_set_props(dc.as_mut(), $props.as_ptr());
}
}
};
@@ -32,9 +28,7 @@ macro_rules! define_property {
// use associated function syntax for type checking
name: ::core::ffi::CStr::as_ptr($name),
info: $prop,
- offset: ::core::mem::offset_of!($state, $field)
- .try_into()
- .expect("Could not fit offset value to type"),
+ offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
@@ -45,47 +39,27 @@ macro_rules! define_property {
// use associated function syntax for type checking
name: ::core::ffi::CStr::as_ptr($name),
info: $prop,
- offset: ::core::mem::offset_of!($state, $field)
- .try_into()
- .expect("Could not fit offset value to type"),
+ offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: false,
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
}
};
}
-#[repr(C)]
-pub struct Properties<const N: usize>(pub OnceLock<[Property; N]>, pub fn() -> [Property; N]);
-
-impl<const N: usize> Properties<N> {
- pub fn as_mut_ptr(&mut self) -> *mut Property {
- _ = self.0.get_or_init(self.1);
- self.0.get_mut().unwrap().as_mut_ptr()
- }
-}
-
#[macro_export]
macro_rules! declare_properties {
($ident:ident, $($prop:expr),*$(,)*) => {
-
- const fn _calc_prop_len() -> usize {
+ pub static $ident: [$crate::bindings::Property; {
let mut len = 1;
$({
_ = stringify!($prop);
len += 1;
})*
len
- }
- const PROP_LEN: usize = _calc_prop_len();
-
- fn _make_properties() -> [$crate::bindings::Property; PROP_LEN] {
- [
- $($prop),*,
- unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() },
- ]
- }
-
- pub static mut $ident: $crate::device_class::Properties<PROP_LEN> = $crate::device_class::Properties(::std::sync::OnceLock::new(), _make_properties);
+ }] = [
+ $($prop),*,
+ unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() },
+ ];
};
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 16/40] rust: provide safe wrapper for MaybeUninit::zeroed()
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (14 preceding siblings ...)
2024-11-04 17:26 ` [PULL 15/40] rust: make properties array immutable Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 17/40] rust: do not use TYPE_CHARDEV unnecessarily Paolo Bonzini
` (24 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
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>
---
rust/hw/char/pl011/src/device_class.rs | 4 ++--
rust/hw/char/pl011/src/memory_ops.rs | 8 ++++----
rust/qemu-api/meson.build | 1 +
rust/qemu-api/src/device_class.rs | 8 ++++----
rust/qemu-api/src/lib.rs | 1 +
rust/qemu-api/src/zeroable.rs | 23 +++++++++++++++++++++++
6 files changed, 35 insertions(+), 10 deletions(-)
create mode 100644 rust/qemu-api/src/zeroable.rs
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index 2ad80451e87..08c846aa482 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -4,7 +4,7 @@
use core::ptr::NonNull;
-use qemu_api::{bindings::*, definitions::ObjectImpl};
+use qemu_api::{bindings::*, definitions::ObjectImpl, zeroable::Zeroable};
use crate::device::PL011State;
@@ -12,7 +12,7 @@
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
name: PL011State::TYPE_INFO.name,
unmigratable: true,
- ..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() }
+ ..Zeroable::ZERO
};
qemu_api::declare_properties! {
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
index 5a5320e66c3..fc69922fbf3 100644
--- a/rust/hw/char/pl011/src/memory_ops.rs
+++ b/rust/hw/char/pl011/src/memory_ops.rs
@@ -2,9 +2,9 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use core::{mem::MaybeUninit, ptr::NonNull};
+use core::ptr::NonNull;
-use qemu_api::bindings::*;
+use qemu_api::{bindings::*, zeroable::Zeroable};
use crate::device::PL011State;
@@ -14,11 +14,11 @@
read_with_attrs: None,
write_with_attrs: None,
endianness: device_endian::DEVICE_NATIVE_ENDIAN,
- valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() },
+ valid: Zeroable::ZERO,
impl_: MemoryRegionOps__bindgen_ty_2 {
min_access_size: 4,
max_access_size: 4,
- ..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() }
+ ..Zeroable::ZERO
},
};
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 1fc36078027..1b0fd406378 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -5,6 +5,7 @@ _qemu_api_rs = static_library(
'src/lib.rs',
'src/definitions.rs',
'src/device_class.rs',
+ 'src/zeroable.rs',
],
{'.' : bindings_rs},
),
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index 4b14cb3ffd6..aa6088d9d3d 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -31,7 +31,7 @@ macro_rules! define_property {
offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
- ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
+ ..$crate::zeroable::Zeroable::ZERO
}
};
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
@@ -41,7 +41,7 @@ macro_rules! define_property {
info: $prop,
offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: false,
- ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }
+ ..$crate::zeroable::Zeroable::ZERO
}
};
}
@@ -58,7 +58,7 @@ macro_rules! declare_properties {
len
}] = [
$($prop),*,
- unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() },
+ $crate::zeroable::Zeroable::ZERO,
];
};
}
@@ -79,7 +79,7 @@ macro_rules! vm_state_description {
$vname.as_ptr()
},)*
unmigratable: true,
- ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::VMStateDescription>::zeroed().assume_init() }
+ ..$crate::zeroable::Zeroable::ZERO
};
}
}
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 6bc68076aae..e94a15bb823 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -29,6 +29,7 @@ unsafe impl Sync for bindings::VMStateDescription {}
pub mod definitions;
pub mod device_class;
+pub mod zeroable;
use std::alloc::{GlobalAlloc, Layout};
diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs
new file mode 100644
index 00000000000..45ec95c9f70
--- /dev/null
+++ b/rust/qemu-api/src/zeroable.rs
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/// Encapsulates the requirement that
+/// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause
+/// undefined behavior.
+///
+/// # Safety
+///
+/// Do not add this trait to a type unless all-zeroes is
+/// a valid value for the type. In particular, remember that raw
+/// pointers can be zero, but references and `NonNull<T>` cannot
+/// unless wrapped with `Option<>`.
+pub unsafe trait Zeroable: Default {
+ /// SAFETY: If the trait was added to a type, then by definition
+ /// this is safe.
+ const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
+}
+
+unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {}
+unsafe impl Zeroable for crate::bindings::Property {}
+unsafe impl Zeroable for crate::bindings::VMStateDescription {}
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {}
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 17/40] rust: do not use TYPE_CHARDEV unnecessarily
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (15 preceding siblings ...)
2024-11-04 17:26 ` [PULL 16/40] rust: provide safe wrapper for MaybeUninit::zeroed() Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 18/40] rust: add definitions for vmstate Paolo Bonzini
` (23 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
In the invocation of qdev_prop_set_chr(), "chardev" is the name of a
property rather than a type and has to match the name of the property
in device_class.rs. Do not use TYPE_CHARDEV here, just like in the C
version of pl011_create.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/pl011/src/device.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 0347a027c5f..b3d8bc004e0 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -573,7 +573,7 @@ pub fn update(&self) {
let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
- qdev_prop_set_chr(dev, bindings::TYPE_CHARDEV.as_ptr(), chr);
+ qdev_prop_set_chr(dev, c"chardev".as_ptr(), chr);
sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
sysbus_mmio_map(sysbus, 0, addr);
sysbus_connect_irq(sysbus, 0, irq);
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 18/40] rust: add definitions for vmstate
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (16 preceding siblings ...)
2024-11-04 17:26 ` [PULL 17/40] rust: do not use TYPE_CHARDEV unnecessarily Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 19/40] rust/pl011: fix default value for migrate-clock Paolo Bonzini
` (22 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
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>
---
rust/qemu-api/meson.build | 1 +
rust/qemu-api/src/device_class.rs | 21 --
rust/qemu-api/src/lib.rs | 3 +
rust/qemu-api/src/vmstate.rs | 360 ++++++++++++++++++++++++++++++
rust/qemu-api/tests/tests.rs | 11 +-
5 files changed, 370 insertions(+), 26 deletions(-)
create mode 100644 rust/qemu-api/src/vmstate.rs
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 1b0fd406378..3b849f7c413 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -5,6 +5,7 @@ _qemu_api_rs = static_library(
'src/lib.rs',
'src/definitions.rs',
'src/device_class.rs',
+ 'src/vmstate.rs',
'src/zeroable.rs',
],
{'.' : bindings_rs},
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index aa6088d9d3d..3d40256f60f 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -62,24 +62,3 @@ macro_rules! declare_properties {
];
};
}
-
-#[macro_export]
-macro_rules! vm_state_description {
- ($(#[$outer:meta])*
- $name:ident,
- $(name: $vname:expr,)*
- $(unmigratable: $um_val:expr,)*
- ) => {
- #[used]
- $(#[$outer])*
- pub static $name: $crate::bindings::VMStateDescription = $crate::bindings::VMStateDescription {
- $(name: {
- #[used]
- static VMSTATE_NAME: &::core::ffi::CStr = $vname;
- $vname.as_ptr()
- },)*
- unmigratable: true,
- ..$crate::zeroable::Zeroable::ZERO
- };
- }
-}
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index e94a15bb823..10ab3d7e639 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -26,9 +26,12 @@ unsafe impl Send for bindings::Property {}
unsafe impl Sync for bindings::Property {}
unsafe impl Sync for bindings::TypeInfo {}
unsafe impl Sync for bindings::VMStateDescription {}
+unsafe impl Sync for bindings::VMStateField {}
+unsafe impl Sync for bindings::VMStateInfo {}
pub mod definitions;
pub mod device_class;
+pub mod vmstate;
pub mod zeroable;
use std::alloc::{GlobalAlloc, Layout};
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
new file mode 100644
index 00000000000..0c1197277f9
--- /dev/null
+++ b/rust/qemu-api/src/vmstate.rs
@@ -0,0 +1,360 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! Helper macros to declare migration state for device models.
+//!
+//! Some macros are direct equivalents to the C macros declared in
+//! `include/migration/vmstate.h` while
+//! [`vmstate_subsections`](crate::vmstate_subsections) and
+//! [`vmstate_fields`](crate::vmstate_fields) are meant to be used when
+//! declaring a device model state struct.
+
+#[doc(alias = "VMSTATE_UNUSED_BUFFER")]
+#[macro_export]
+macro_rules! vmstate_unused_buffer {
+ ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
+ $crate::bindings::VMStateField {
+ name: c"unused".as_ptr(),
+ err_hint: ::core::ptr::null(),
+ offset: 0,
+ size: $size,
+ start: 0,
+ num: 0,
+ num_offset: 0,
+ size_offset: 0,
+ info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
+ flags: VMStateFlags::VMS_BUFFER,
+ vmsd: ::core::ptr::null(),
+ version_id: $version_id,
+ struct_version_id: 0,
+ field_exists: $field_exists_fn,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_UNUSED_V")]
+#[macro_export]
+macro_rules! vmstate_unused_v {
+ ($version_id:expr, $size:expr) => {{
+ $crate::vmstate_unused_buffer!(None, $version_id, $size)
+ }};
+}
+
+#[doc(alias = "VMSTATE_UNUSED")]
+#[macro_export]
+macro_rules! vmstate_unused {
+ ($size:expr) => {{
+ $crate::vmstate_unused_v!(0, $size)
+ }};
+}
+
+#[doc(alias = "VMSTATE_SINGLE_TEST")]
+#[macro_export]
+macro_rules! vmstate_single_test {
+ ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{
+ $crate::bindings::VMStateField {
+ name: ::core::concat!(::core::stringify!($field_name), 0)
+ .as_bytes()
+ .as_ptr() as *const ::core::ffi::c_char,
+ err_hint: ::core::ptr::null(),
+ offset: ::core::mem::offset_of!($struct_name, $field_name),
+ size: $size,
+ start: 0,
+ num: 0,
+ num_offset: 0,
+ size_offset: 0,
+ info: unsafe { $info },
+ flags: VMStateFlags::VMS_SINGLE,
+ vmsd: ::core::ptr::null(),
+ version_id: $version_id,
+ struct_version_id: 0,
+ field_exists: $field_exists_fn,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_SINGLE")]
+#[macro_export]
+macro_rules! vmstate_single {
+ ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{
+ $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size)
+ }};
+}
+
+#[doc(alias = "VMSTATE_UINT32_V")]
+#[macro_export]
+macro_rules! vmstate_uint32_v {
+ ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
+ $crate::vmstate_single!(
+ $field_name,
+ $struct_name,
+ $version_id,
+ ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
+ ::core::mem::size_of::<u32>()
+ )
+ }};
+}
+
+#[doc(alias = "VMSTATE_UINT32")]
+#[macro_export]
+macro_rules! vmstate_uint32 {
+ ($field_name:ident, $struct_name:ty) => {{
+ $crate::vmstate_uint32_v!($field_name, $struct_name, 0)
+ }};
+}
+
+#[doc(alias = "VMSTATE_INT32_V")]
+#[macro_export]
+macro_rules! vmstate_int32_v {
+ ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
+ $crate::vmstate_single!(
+ $field_name,
+ $struct_name,
+ $version_id,
+ ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32),
+ ::core::mem::size_of::<i32>()
+ )
+ }};
+}
+
+#[doc(alias = "VMSTATE_INT32")]
+#[macro_export]
+macro_rules! vmstate_int32 {
+ ($field_name:ident, $struct_name:ty) => {{
+ $crate::vmstate_int32_v!($field_name, $struct_name, 0)
+ }};
+}
+
+#[doc(alias = "VMSTATE_ARRAY")]
+#[macro_export]
+macro_rules! vmstate_array {
+ ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{
+ $crate::bindings::VMStateField {
+ name: ::core::concat!(::core::stringify!($field_name), 0)
+ .as_bytes()
+ .as_ptr() as *const ::core::ffi::c_char,
+ err_hint: ::core::ptr::null(),
+ offset: ::core::mem::offset_of!($struct_name, $field_name),
+ size: $size,
+ start: 0,
+ num: $length as _,
+ num_offset: 0,
+ size_offset: 0,
+ info: unsafe { $info },
+ flags: VMStateFlags::VMS_ARRAY,
+ vmsd: ::core::ptr::null(),
+ version_id: $version_id,
+ struct_version_id: 0,
+ field_exists: None,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_UINT32_ARRAY_V")]
+#[macro_export]
+macro_rules! vmstate_uint32_array_v {
+ ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{
+ $crate::vmstate_array!(
+ $field_name,
+ $struct_name,
+ $length,
+ $version_id,
+ ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
+ ::core::mem::size_of::<u32>()
+ )
+ }};
+}
+
+#[doc(alias = "VMSTATE_UINT32_ARRAY")]
+#[macro_export]
+macro_rules! vmstate_uint32_array {
+ ($field_name:ident, $struct_name:ty, $length:expr) => {{
+ $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0)
+ }};
+}
+
+#[doc(alias = "VMSTATE_STRUCT_POINTER_V")]
+#[macro_export]
+macro_rules! vmstate_struct_pointer_v {
+ ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{
+ $crate::bindings::VMStateField {
+ name: ::core::concat!(::core::stringify!($field_name), 0)
+ .as_bytes()
+ .as_ptr() as *const ::core::ffi::c_char,
+ err_hint: ::core::ptr::null(),
+ offset: ::core::mem::offset_of!($struct_name, $field_name),
+ size: ::core::mem::size_of::<*const $type>(),
+ start: 0,
+ num: 0,
+ num_offset: 0,
+ size_offset: 0,
+ info: ::core::ptr::null(),
+ flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
+ vmsd: unsafe { $vmsd },
+ version_id: $version_id,
+ struct_version_id: 0,
+ field_exists: None,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_ARRAY_OF_POINTER")]
+#[macro_export]
+macro_rules! vmstate_array_of_pointer {
+ ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{
+ $crate::bindings::VMStateField {
+ name: ::core::concat!(::core::stringify!($field_name), 0)
+ .as_bytes()
+ .as_ptr() as *const ::core::ffi::c_char,
+ version_id: $version_id,
+ num: $num as _,
+ info: unsafe { $info },
+ size: ::core::mem::size_of::<*const $type>(),
+ flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
+ offset: ::core::mem::offset_of!($struct_name, $field_name),
+ err_hint: ::core::ptr::null(),
+ start: 0,
+ num_offset: 0,
+ size_offset: 0,
+ vmsd: ::core::ptr::null(),
+ struct_version_id: 0,
+ field_exists: None,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")]
+#[macro_export]
+macro_rules! vmstate_array_of_pointer_to_struct {
+ ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{
+ $crate::bindings::VMStateField {
+ name: ::core::concat!(::core::stringify!($field_name), 0)
+ .as_bytes()
+ .as_ptr() as *const ::core::ffi::c_char,
+ version_id: $version_id,
+ num: $num as _,
+ vmsd: unsafe { $vmsd },
+ size: ::core::mem::size_of::<*const $type>(),
+ flags: VMStateFlags(
+ VMStateFlags::VMS_ARRAY.0
+ | VMStateFlags::VMS_STRUCT.0
+ | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
+ ),
+ offset: ::core::mem::offset_of!($struct_name, $field_name),
+ err_hint: ::core::ptr::null(),
+ start: 0,
+ num_offset: 0,
+ size_offset: 0,
+ vmsd: ::core::ptr::null(),
+ struct_version_id: 0,
+ field_exists: None,
+ }
+ }};
+}
+
+#[doc(alias = "VMSTATE_CLOCK_V")]
+#[macro_export]
+macro_rules! vmstate_clock_v {
+ ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
+ $crate::vmstate_struct_pointer_v!(
+ $field_name,
+ $struct_name,
+ $version_id,
+ ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
+ $crate::bindings::Clock
+ )
+ }};
+}
+
+#[doc(alias = "VMSTATE_CLOCK")]
+#[macro_export]
+macro_rules! vmstate_clock {
+ ($field_name:ident, $struct_name:ty) => {{
+ $crate::vmstate_clock_v!($field_name, $struct_name, 0)
+ }};
+}
+
+#[doc(alias = "VMSTATE_ARRAY_CLOCK_V")]
+#[macro_export]
+macro_rules! vmstate_array_clock_v {
+ ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{
+ $crate::vmstate_array_of_pointer_to_struct!(
+ $field_name,
+ $struct_name,
+ $num,
+ $version_id,
+ ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
+ $crate::bindings::Clock
+ )
+ }};
+}
+
+#[doc(alias = "VMSTATE_ARRAY_CLOCK")]
+#[macro_export]
+macro_rules! vmstate_array_clock {
+ ($field_name:ident, $struct_name:ty, $num:expr) => {{
+ $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0)
+ }};
+}
+
+/// Helper macro to declare a list of
+/// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
+/// a pointer to the array of values it created.
+#[macro_export]
+macro_rules! vmstate_fields {
+ ($($field:expr),*$(,)*) => {{
+ static _FIELDS: &[$crate::bindings::VMStateField] = &[
+ $($field),*,
+ $crate::bindings::VMStateField {
+ name: ::core::ptr::null(),
+ err_hint: ::core::ptr::null(),
+ offset: 0,
+ size: 0,
+ start: 0,
+ num: 0,
+ num_offset: 0,
+ size_offset: 0,
+ info: ::core::ptr::null(),
+ flags: VMStateFlags::VMS_END,
+ vmsd: ::core::ptr::null(),
+ version_id: 0,
+ struct_version_id: 0,
+ field_exists: None,
+ }
+ ];
+ _FIELDS.as_ptr()
+ }}
+}
+
+/// A transparent wrapper type for the `subsections` field of
+/// [`VMStateDescription`](crate::bindings::VMStateDescription).
+///
+/// This is necessary to be able to declare subsection descriptions as statics,
+/// because the only way to implement `Sync` for a foreign type (and `*const`
+/// pointers are foreign types in Rust) is to create a wrapper struct and
+/// `unsafe impl Sync` for it.
+///
+/// This struct is used in the
+/// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
+#[repr(transparent)]
+pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
+
+unsafe impl Sync for VMStateSubsectionsWrapper {}
+
+/// Helper macro to declare a list of subsections
+/// ([`VMStateDescription`](`crate::bindings::VMStateDescription`)) into a
+/// static and return a pointer to the array of pointers it created.
+#[macro_export]
+macro_rules! vmstate_subsections {
+ ($($subsection:expr),*$(,)*) => {{
+ static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
+ $({
+ static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
+ ::core::ptr::addr_of!(_SUBSECTION)
+ }),*,
+ ::core::ptr::null()
+ ]);
+ _SUBSECTIONS.0.as_ptr()
+ }}
+}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index aa1e0568c69..37c4dd44f81 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -8,17 +8,18 @@
bindings::*,
declare_properties, define_property,
definitions::{Class, ObjectImpl},
- device_class_init, vm_state_description,
+ device_class_init,
+ zeroable::Zeroable,
};
#[test]
fn test_device_decl_macros() {
// Test that macros can compile.
- vm_state_description! {
- VMSTATE,
- name: c"name",
+ pub static VMSTATE: VMStateDescription = VMStateDescription {
+ name: c"name".as_ptr(),
unmigratable: true,
- }
+ ..Zeroable::ZERO
+ };
#[repr(C)]
#[derive(qemu_api_macros::Object)]
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 19/40] rust/pl011: fix default value for migrate-clock
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (17 preceding siblings ...)
2024-11-04 17:26 ` [PULL 18/40] rust: add definitions for vmstate Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:26 ` [PULL 20/40] rust/pl011: add support for migration Paolo Bonzini
` (21 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/pl011/src/device_class.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index 08c846aa482..9282dc4d151 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -29,7 +29,8 @@
PL011State,
migrate_clock,
unsafe { &qdev_prop_bool },
- bool
+ bool,
+ default = true
),
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 20/40] rust/pl011: add support for migration
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (18 preceding siblings ...)
2024-11-04 17:26 ` [PULL 19/40] rust/pl011: fix default value for migrate-clock Paolo Bonzini
@ 2024-11-04 17:26 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 21/40] rust/pl011: move CLK_NAME static to function scope Paolo Bonzini
` (20 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:26 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Declare the vmstate description of the PL011 device.
Based on 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>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-4-051e7a25b978@linaro.org
---
rust/hw/char/pl011/src/device.rs | 27 ++++++++++
rust/hw/char/pl011/src/device_class.rs | 73 +++++++++++++++++++++++---
rust/hw/char/pl011/src/lib.rs | 1 +
3 files changed, 95 insertions(+), 6 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index b3d8bc004e0..dd9145669dc 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -20,6 +20,12 @@
static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
+/// Integer Baud Rate Divider, `UARTIBRD`
+const IBRD_MASK: u32 = 0x3f;
+
+/// Fractional Baud Rate Divider, `UARTFBRD`
+const FBRD_MASK: u32 = 0xffff;
+
const DATA_BREAK: u32 = 1 << 10;
/// QEMU sourced constant.
@@ -492,6 +498,27 @@ pub fn update(&self) {
unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
}
}
+
+ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
+ /* Sanity-check input state */
+ if self.read_pos >= self.read_fifo.len() || self.read_count > self.read_fifo.len() {
+ return Err(());
+ }
+
+ if !self.fifo_enabled() && self.read_count > 0 && self.read_pos > 0 {
+ // Older versions of PL011 didn't ensure that the single
+ // character in the FIFO in FIFO-disabled mode is in
+ // element 0 of the array; convert to follow the current
+ // code's assumptions.
+ self.read_fifo[0] = self.read_fifo[self.read_pos];
+ self.read_pos = 0;
+ }
+
+ self.ibrd &= IBRD_MASK;
+ self.fbrd &= FBRD_MASK;
+
+ Ok(())
+ }
}
/// Which bits in the interrupt status matter for each outbound IRQ line ?
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index 9282dc4d151..6a554ad7926 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -2,16 +2,77 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use core::ptr::NonNull;
+use core::{
+ ffi::{c_int, c_void},
+ ptr::NonNull,
+};
-use qemu_api::{bindings::*, definitions::ObjectImpl, zeroable::Zeroable};
+use qemu_api::{
+ bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32,
+ vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
+};
-use crate::device::PL011State;
+use crate::device::{PL011State, PL011_FIFO_DEPTH};
+
+extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_ref().migrate_clock
+ }
+}
+
+/// Migration subsection for [`PL011State`] clock.
+pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
+ name: c"pl011/clock".as_ptr(),
+ version_id: 1,
+ minimum_version_id: 1,
+ needed: Some(pl011_clock_needed),
+ fields: vmstate_fields! {
+ vmstate_clock!(clock, PL011State),
+ },
+ ..Zeroable::ZERO
+};
+
+extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ let result = state.as_mut().post_load(version_id as u32);
+ if result.is_err() {
+ -1
+ } else {
+ 0
+ }
+ }
+}
-#[used]
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
- name: PL011State::TYPE_INFO.name,
- unmigratable: true,
+ name: c"pl011".as_ptr(),
+ version_id: 2,
+ minimum_version_id: 2,
+ post_load: Some(pl011_post_load),
+ fields: vmstate_fields! {
+ vmstate_unused!(core::mem::size_of::<u32>()),
+ vmstate_uint32!(flags, PL011State),
+ vmstate_uint32!(line_control, PL011State),
+ vmstate_uint32!(receive_status_error_clear, PL011State),
+ vmstate_uint32!(control, PL011State),
+ vmstate_uint32!(dmacr, PL011State),
+ vmstate_uint32!(int_enabled, PL011State),
+ vmstate_uint32!(int_level, PL011State),
+ vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH),
+ vmstate_uint32!(ilpr, PL011State),
+ vmstate_uint32!(ibrd, PL011State),
+ vmstate_uint32!(fbrd, PL011State),
+ vmstate_uint32!(ifl, PL011State),
+ vmstate_int32!(read_pos, PL011State),
+ vmstate_int32!(read_count, PL011State),
+ vmstate_int32!(read_trigger, PL011State),
+ },
+ subsections: vmstate_subsections! {
+ VMSTATE_PL011_CLOCK
+ },
..Zeroable::ZERO
};
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
index 2939ee50c99..73474a07e7c 100644
--- a/rust/hw/char/pl011/src/lib.rs
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -36,6 +36,7 @@
clippy::cognitive_complexity,
clippy::missing_safety_doc,
)]
+#![allow(clippy::result_unit_err)]
extern crate bilge;
extern crate bilge_impl;
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 21/40] rust/pl011: move CLK_NAME static to function scope
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (19 preceding siblings ...)
2024-11-04 17:26 ` [PULL 20/40] rust/pl011: add support for migration Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 22/40] rust/pl011: add TYPE_PL011_LUMINARY device Paolo Bonzini
` (19 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
We do not need to have CLK_NAME public nor a static. No functional change.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-5-051e7a25b978@linaro.org
---
rust/hw/char/pl011/src/device.rs | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index dd9145669dc..f91790ff185 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -102,9 +102,6 @@ impl qemu_api::definitions::Class for PL011Class {
> = None;
}
-#[used]
-pub static CLK_NAME: &CStr = c"clk";
-
impl PL011State {
/// Initializes a pre-allocated, unitialized instance of `PL011State`.
///
@@ -114,7 +111,9 @@ impl PL011State {
/// `PL011State` type. It must not be called more than once on the same
/// location/instance. All its fields are expected to hold unitialized
/// values with the sole exception of `parent_obj`.
- pub unsafe fn init(&mut self) {
+ unsafe fn init(&mut self) {
+ const CLK_NAME: &CStr = c"clk";
+
let dev = addr_of_mut!(*self).cast::<DeviceState>();
// SAFETY:
//
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 22/40] rust/pl011: add TYPE_PL011_LUMINARY device
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (20 preceding siblings ...)
2024-11-04 17:27 ` [PULL 21/40] rust/pl011: move CLK_NAME static to function scope Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 23/40] rust/pl011: remove commented out C code Paolo Bonzini
` (18 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Add a device specialization for the Luminary UART device.
This commit adds a DeviceId enum that utilizes the Index trait to return
different bytes depending on what device id the UART has (Arm -default-
or Luminary)
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-6-051e7a25b978@linaro.org
---
rust/hw/char/pl011/src/device.rs | 77 ++++++++++++++++++++++++++++++--
rust/hw/char/pl011/src/lib.rs | 1 +
2 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index f91790ff185..051c59f39ae 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -18,8 +18,6 @@
RegisterOffset,
};
-static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
-
/// Integer Baud Rate Divider, `UARTIBRD`
const IBRD_MASK: u32 = 0x3f;
@@ -31,6 +29,29 @@
/// QEMU sourced constant.
pub const PL011_FIFO_DEPTH: usize = 16_usize;
+#[derive(Clone, Copy, Debug)]
+enum DeviceId {
+ #[allow(dead_code)]
+ Arm = 0,
+ Luminary,
+}
+
+impl std::ops::Index<hwaddr> for DeviceId {
+ type Output = c_uchar;
+
+ fn index(&self, idx: hwaddr) -> &Self::Output {
+ match self {
+ Self::Arm => &Self::PL011_ID_ARM[idx as usize],
+ Self::Luminary => &Self::PL011_ID_LUMINARY[idx as usize],
+ }
+ }
+}
+
+impl DeviceId {
+ const PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
+ const PL011_ID_LUMINARY: [c_uchar; 8] = [0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1];
+}
+
#[repr(C)]
#[derive(Debug, qemu_api_macros::Object)]
/// PL011 Device Model in QEMU
@@ -75,6 +96,8 @@ pub struct PL011State {
pub clock: NonNull<Clock>,
#[doc(alias = "migrate_clk")]
pub migrate_clock: bool,
+ /// The byte string that identifies the device.
+ device_id: DeviceId,
}
impl ObjectImpl for PL011State {
@@ -162,7 +185,7 @@ pub fn read(
std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
Err(v) if (0x3f8..0x400).contains(&v) => {
- u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize])
+ u64::from(self.device_id[(offset - 0xfe0) >> 2])
}
Err(_) => {
// qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
@@ -619,3 +642,51 @@ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
state.as_mut().init();
}
}
+
+#[repr(C)]
+#[derive(Debug, qemu_api_macros::Object)]
+/// PL011 Luminary device model.
+pub struct PL011Luminary {
+ parent_obj: PL011State,
+}
+
+#[repr(C)]
+pub struct PL011LuminaryClass {
+ _inner: [u8; 0],
+}
+
+/// Initializes a pre-allocated, unitialized instance of `PL011Luminary`.
+///
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011Luminary`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+pub unsafe extern "C" fn pl011_luminary_init(obj: *mut Object) {
+ unsafe {
+ debug_assert!(!obj.is_null());
+ let mut state = NonNull::new_unchecked(obj.cast::<PL011Luminary>());
+ let state = state.as_mut();
+ state.parent_obj.device_id = DeviceId::Luminary;
+ }
+}
+
+impl qemu_api::definitions::Class for PL011LuminaryClass {
+ const CLASS_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = None;
+ const CLASS_BASE_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = None;
+}
+
+impl ObjectImpl for PL011Luminary {
+ type Class = PL011LuminaryClass;
+ const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
+ const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY;
+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(crate::TYPE_PL011);
+ const ABSTRACT: bool = false;
+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = Some(pl011_luminary_init);
+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
index 73474a07e7c..fb33110d3d8 100644
--- a/rust/hw/char/pl011/src/lib.rs
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -47,6 +47,7 @@
pub mod memory_ops;
pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
+pub const TYPE_PL011_LUMINARY: &::core::ffi::CStr = c"pl011_luminary";
/// Offset of each register from the base memory address of the device.
///
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 23/40] rust/pl011: remove commented out C code
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (21 preceding siblings ...)
2024-11-04 17:27 ` [PULL 22/40] rust/pl011: add TYPE_PL011_LUMINARY device Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 24/40] rust/pl011: Use correct masks for IBRD and FBRD Paolo Bonzini
` (17 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This code juxtaposed what should be happening according to the C device
model but is not needed now that this has been reviewed (I hope) and its
validity checked against what the C device does (I hope, again).
No functional change.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-8-051e7a25b978@linaro.org
---
rust/hw/char/pl011/src/device.rs | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 051c59f39ae..98357db04e8 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -192,7 +192,6 @@ pub fn read(
0
}
Ok(DR) => {
- // s->flags &= ~PL011_FLAG_RXFF;
self.flags.set_receive_fifo_full(false);
let c = self.read_fifo[self.read_pos];
if self.read_count > 0 {
@@ -200,11 +199,9 @@ pub fn read(
self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
}
if self.read_count == 0 {
- // self.flags |= PL011_FLAG_RXFE;
self.flags.set_receive_fifo_empty(true);
}
if self.read_count + 1 == self.read_trigger {
- //self.int_level &= ~ INT_RX;
self.int_level &= !registers::INT_RX;
}
// Update error bits.
@@ -374,13 +371,6 @@ fn loopback_mdmctrl(&mut self) {
* dealt with here.
*/
- //fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
- // PL011_FLAG_DSR | PL011_FLAG_CTS);
- //fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
- //fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
- //fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
- //fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
- //
self.flags.set_ring_indicator(self.control.out_2());
self.flags.set_data_carrier_detect(self.control.out_1());
self.flags.set_clear_to_send(self.control.request_to_send());
@@ -391,10 +381,6 @@ fn loopback_mdmctrl(&mut self) {
let mut il = self.int_level;
il &= !Interrupt::MS;
- //il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
- //il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
- //il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
- //il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
if self.flags.data_set_ready() {
il |= Interrupt::DSR as u32;
@@ -500,10 +486,8 @@ pub fn put_fifo(&mut self, value: c_uint) {
let slot = (self.read_pos + self.read_count) & (depth - 1);
self.read_fifo[slot] = value;
self.read_count += 1;
- // s->flags &= ~PL011_FLAG_RXFE;
self.flags.set_receive_fifo_empty(false);
if self.read_count == depth {
- //s->flags |= PL011_FLAG_RXFF;
self.flags.set_receive_fifo_full(true);
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 24/40] rust/pl011: Use correct masks for IBRD and FBRD
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (22 preceding siblings ...)
2024-11-04 17:27 ` [PULL 23/40] rust/pl011: remove commented out C code Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 25/40] rust: patch bilge-impl to allow compilation with 1.63.0 Paolo Bonzini
` (16 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Port fix from commit cd247eae16ab1b9ce97fd34c000c1b883feeda45
"hw/char/pl011: Use correct masks for IBRD and FBRD"
Related issue: <https://gitlab.com/qemu-project/qemu/-/issues/2610>
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-9-051e7a25b978@linaro.org
---
rust/hw/char/pl011/src/device.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 98357db04e8..788b47203b1 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -19,10 +19,10 @@
};
/// Integer Baud Rate Divider, `UARTIBRD`
-const IBRD_MASK: u32 = 0x3f;
+const IBRD_MASK: u32 = 0xffff;
/// Fractional Baud Rate Divider, `UARTFBRD`
-const FBRD_MASK: u32 = 0xffff;
+const FBRD_MASK: u32 = 0x3f;
const DATA_BREAK: u32 = 1 << 10;
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 25/40] rust: patch bilge-impl to allow compilation with 1.63.0
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (23 preceding siblings ...)
2024-11-04 17:27 ` [PULL 24/40] rust/pl011: Use correct masks for IBRD and FBRD Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 26/40] rust: fix cfgs of proc-macro2 for 1.63.0 Paolo Bonzini
` (15 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Apply a patch that removes "let ... else" constructs, replacing them with
"if let ... else" or "let ... = match ...". "let ... else" was stabilized in
Rust 1.65.0.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
.gitattributes | 2 +
subprojects/bilge-impl-0.2-rs.wrap | 1 +
.../packagefiles/bilge-impl-1.63.0.patch | 45 +++++++++++++++++++
3 files changed, 48 insertions(+)
create mode 100644 subprojects/packagefiles/bilge-impl-1.63.0.patch
diff --git a/.gitattributes b/.gitattributes
index 6dc6383d3d1..9ce7a19581a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -5,3 +5,5 @@
*.rs diff=rust
*.rs.inc diff=rust
Cargo.lock diff=toml merge=binary
+
+*.patch -text -whitespace
diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap
index eefb10c36c2..b24c34a9043 100644
--- a/subprojects/bilge-impl-0.2-rs.wrap
+++ b/subprojects/bilge-impl-0.2-rs.wrap
@@ -5,3 +5,4 @@ source_filename = bilge-impl-0.2.0.tar.gz
source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8
#method = cargo
patch_directory = bilge-impl-0.2-rs
+diff_files = bilge-impl-1.63.0.patch
diff --git a/subprojects/packagefiles/bilge-impl-1.63.0.patch b/subprojects/packagefiles/bilge-impl-1.63.0.patch
new file mode 100644
index 00000000000..987428a6d65
--- /dev/null
+++ b/subprojects/packagefiles/bilge-impl-1.63.0.patch
@@ -0,0 +1,45 @@
+--- a/src/shared/discriminant_assigner.rs
++++ b/src/shared/discriminant_assigner.rs
+@@ -26,20 +26,20 @@
+ let discriminant_expr = &discriminant.1;
+ let variant_name = &variant.ident;
+
+- let Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) = discriminant_expr else {
++ if let Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) = discriminant_expr {
++ let discriminant_value: u128 = int.base10_parse().unwrap_or_else(unreachable);
++ if discriminant_value > self.max_value() {
++ abort!(variant, "Value of variant exceeds the given number of bits")
++ }
++
++ Some(discriminant_value)
++ } else {
+ abort!(
+ discriminant_expr,
+ "variant `{}` is not a number", variant_name;
+ help = "only literal integers currently supported"
+ )
+- };
+-
+- let discriminant_value: u128 = int.base10_parse().unwrap_or_else(unreachable);
+- if discriminant_value > self.max_value() {
+- abort!(variant, "Value of variant exceeds the given number of bits")
+ }
+-
+- Some(discriminant_value)
+ }
+
+ fn assign(&mut self, variant: &Variant) -> u128 {
+--- a/src/shared/fallback.rs
++++ b/src/shared/fallback.rs
+@@ -22,8 +22,9 @@
+ }
+ Unnamed(fields) => {
+ let variant_fields = fields.unnamed.iter();
+- let Ok(fallback_value) = variant_fields.exactly_one() else {
+- abort!(variant, "fallback variant must have exactly one field"; help = "use only one field or change to a unit variant")
++ let fallback_value = match variant_fields.exactly_one() {
++ Ok(ok) => ok,
++ _ => abort!(variant, "fallback variant must have exactly one field"; help = "use only one field or change to a unit variant")
+ };
+
+ if !is_last_variant {
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 26/40] rust: fix cfgs of proc-macro2 for 1.63.0
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (24 preceding siblings ...)
2024-11-04 17:27 ` [PULL 25/40] rust: patch bilge-impl to allow compilation with 1.63.0 Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 27/40] rust: use std::os::raw instead of core::ffi Paolo Bonzini
` (14 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Replay the configuration that would be computed by build.rs when compiling
on a 1.63.0 compiler.
Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
subprojects/packagefiles/proc-macro2-1-rs/meson.build | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
index 818ec59336b..8e601b50ccc 100644
--- a/subprojects/packagefiles/proc-macro2-1-rs/meson.build
+++ b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
@@ -15,7 +15,9 @@ _proc_macro2_rs = static_library(
rust_abi: 'rust',
rust_args: [
'--cfg', 'feature="proc-macro"',
- '--cfg', 'span_locations',
+ '--cfg', 'no_literal_byte_character',
+ '--cfg', 'no_literal_c_string',
+ '--cfg', 'no_source_text',
'--cfg', 'wrap_proc_macro',
],
dependencies: [
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 27/40] rust: use std::os::raw instead of core::ffi
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (25 preceding siblings ...)
2024-11-04 17:27 ` [PULL 26/40] rust: fix cfgs of proc-macro2 for 1.63.0 Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 28/40] rust: introduce a c_str macro Paolo Bonzini
` (13 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
core::ffi::c_* types were introduced in Rust 1.64.0. Use the older types
in std::os::raw, which are now aliases of the types in core::ffi. There is
no need to compile QEMU as no_std, so this is acceptable as long as we support
a version of Debian with Rust 1.63.0.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 3 +--
rust/hw/char/pl011/src/device.rs | 35 +++++++++++-----------------
rust/hw/char/pl011/src/lib.rs | 4 ++--
rust/hw/char/pl011/src/memory_ops.rs | 14 +++--------
rust/qemu-api/src/definitions.rs | 2 +-
rust/qemu-api/src/device_class.rs | 6 ++---
rust/qemu-api/src/lib.rs | 11 +++++----
rust/qemu-api/src/vmstate.rs | 10 ++++----
rust/qemu-api/tests/tests.rs | 9 ++++---
9 files changed, 39 insertions(+), 55 deletions(-)
diff --git a/meson.build b/meson.build
index d360120b233..aa0b0fc5584 100644
--- a/meson.build
+++ b/meson.build
@@ -3947,14 +3947,13 @@ if have_rust and have_system
bindgen_args = [
'--disable-header-comment',
'--raw-line', '// @generated',
- '--ctypes-prefix', 'core::ffi',
+ '--ctypes-prefix', 'std::os::raw',
'--formatter', 'rustfmt',
'--generate-block',
'--generate-cstr',
'--impl-debug',
'--merge-extern-blocks',
'--no-doc-comments',
- '--use-core',
'--with-derive-default',
'--no-layout-tests',
'--no-prepend-enum-name',
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 788b47203b1..036757f7f3a 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -2,9 +2,10 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use core::{
- ffi::{c_int, c_uchar, c_uint, c_void, CStr},
- ptr::{addr_of, addr_of_mut, NonNull},
+use core::ptr::{addr_of, addr_of_mut, NonNull};
+use std::{
+ ffi::CStr,
+ os::raw::{c_int, c_uchar, c_uint, c_void},
};
use qemu_api::{
@@ -117,11 +118,10 @@ pub struct PL011Class {
}
impl qemu_api::definitions::Class for PL011Class {
- const CLASS_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
- > = Some(crate::device_class::pl011_class_init);
+ const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)> =
+ Some(crate::device_class::pl011_class_init);
const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
> = None;
}
@@ -176,11 +176,7 @@ unsafe fn init(&mut self) {
}
}
- pub fn read(
- &mut self,
- offset: hwaddr,
- _size: core::ffi::c_uint,
- ) -> std::ops::ControlFlow<u64, u64> {
+ pub fn read(&mut self, offset: hwaddr, _size: c_uint) -> std::ops::ControlFlow<u64, u64> {
use RegisterOffset::*;
std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
@@ -562,11 +558,7 @@ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
/// readable/writeable from one thread at any time.
///
/// The buffer and size arguments must also be valid.
-pub unsafe extern "C" fn pl011_receive(
- opaque: *mut core::ffi::c_void,
- buf: *const u8,
- size: core::ffi::c_int,
-) {
+pub unsafe extern "C" fn pl011_receive(opaque: *mut c_void, buf: *const u8, size: c_int) {
unsafe {
debug_assert!(!opaque.is_null());
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
@@ -585,7 +577,7 @@ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
-pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
+pub unsafe extern "C" fn pl011_event(opaque: *mut c_void, event: QEMUChrEvent) {
unsafe {
debug_assert!(!opaque.is_null());
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
@@ -656,11 +648,10 @@ pub struct PL011LuminaryClass {
}
impl qemu_api::definitions::Class for PL011LuminaryClass {
- const CLASS_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
- > = None;
+ const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)> =
+ None;
const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
> = None;
}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
index fb33110d3d8..69e96d72854 100644
--- a/rust/hw/char/pl011/src/lib.rs
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -46,8 +46,8 @@
pub mod device_class;
pub mod memory_ops;
-pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
-pub const TYPE_PL011_LUMINARY: &::core::ffi::CStr = c"pl011_luminary";
+pub const TYPE_PL011: &::std::ffi::CStr = c"pl011";
+pub const TYPE_PL011_LUMINARY: &::std::ffi::CStr = c"pl011_luminary";
/// Offset of each register from the base memory address of the device.
///
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
index fc69922fbf3..169d485a4d2 100644
--- a/rust/hw/char/pl011/src/memory_ops.rs
+++ b/rust/hw/char/pl011/src/memory_ops.rs
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use core::ptr::NonNull;
+use std::os::raw::{c_uint, c_void};
use qemu_api::{bindings::*, zeroable::Zeroable};
@@ -22,11 +23,7 @@
},
};
-unsafe extern "C" fn pl011_read(
- opaque: *mut core::ffi::c_void,
- addr: hwaddr,
- size: core::ffi::c_uint,
-) -> u64 {
+unsafe extern "C" fn pl011_read(opaque: *mut c_void, addr: hwaddr, size: c_uint) -> u64 {
assert!(!opaque.is_null());
let mut state = unsafe { NonNull::new_unchecked(opaque.cast::<PL011State>()) };
let val = unsafe { state.as_mut().read(addr, size) };
@@ -43,12 +40,7 @@
}
}
-unsafe extern "C" fn pl011_write(
- opaque: *mut core::ffi::c_void,
- addr: hwaddr,
- data: u64,
- _size: core::ffi::c_uint,
-) {
+unsafe extern "C" fn pl011_write(opaque: *mut c_void, addr: hwaddr, data: u64, _size: c_uint) {
unsafe {
assert!(!opaque.is_null());
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
index 064afe60549..26597934bbd 100644
--- a/rust/qemu-api/src/definitions.rs
+++ b/rust/qemu-api/src/definitions.rs
@@ -4,7 +4,7 @@
//! Definitions required by QEMU when registering a device.
-use ::core::ffi::{c_void, CStr};
+use std::{ffi::CStr, os::raw::c_void};
use crate::bindings::{Object, ObjectClass, TypeInfo};
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index 3d40256f60f..cb4573ca6ef 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -7,7 +7,7 @@ macro_rules! device_class_init {
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
pub unsafe extern "C" fn $func(
klass: *mut $crate::bindings::ObjectClass,
- _: *mut ::core::ffi::c_void,
+ _: *mut ::std::os::raw::c_void,
) {
let mut dc =
::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap();
@@ -26,7 +26,7 @@ macro_rules! define_property {
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
$crate::bindings::Property {
// use associated function syntax for type checking
- name: ::core::ffi::CStr::as_ptr($name),
+ name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: true,
@@ -37,7 +37,7 @@ macro_rules! define_property {
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
$crate::bindings::Property {
// use associated function syntax for type checking
- name: ::core::ffi::CStr::as_ptr($name),
+ name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: false,
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 10ab3d7e639..ed840ee2f72 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -34,7 +34,10 @@ unsafe impl Sync for bindings::VMStateInfo {}
pub mod vmstate;
pub mod zeroable;
-use std::alloc::{GlobalAlloc, Layout};
+use std::{
+ alloc::{GlobalAlloc, Layout},
+ os::raw::c_void,
+};
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
extern "C" {
@@ -48,8 +51,8 @@ fn g_aligned_alloc0(
#[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
extern "C" {
- fn qemu_memalign(alignment: usize, size: usize) -> *mut ::core::ffi::c_void;
- fn qemu_vfree(ptr: *mut ::core::ffi::c_void);
+ fn qemu_memalign(alignment: usize, size: usize) -> *mut c_void;
+ fn qemu_vfree(ptr: *mut c_void);
}
extern "C" {
@@ -114,7 +117,7 @@ fn default() -> Self {
}
// Sanity check.
-const _: [(); 8] = [(); ::core::mem::size_of::<*mut ::core::ffi::c_void>()];
+const _: [(); 8] = [(); ::core::mem::size_of::<*mut c_void>()];
unsafe impl GlobalAlloc for QemuAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 0c1197277f9..4e06e40505f 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -56,7 +56,7 @@ macro_rules! vmstate_single_test {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), 0)
.as_bytes()
- .as_ptr() as *const ::core::ffi::c_char,
+ .as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
offset: ::core::mem::offset_of!($struct_name, $field_name),
size: $size,
@@ -133,7 +133,7 @@ macro_rules! vmstate_array {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), 0)
.as_bytes()
- .as_ptr() as *const ::core::ffi::c_char,
+ .as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
offset: ::core::mem::offset_of!($struct_name, $field_name),
size: $size,
@@ -181,7 +181,7 @@ macro_rules! vmstate_struct_pointer_v {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), 0)
.as_bytes()
- .as_ptr() as *const ::core::ffi::c_char,
+ .as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
offset: ::core::mem::offset_of!($struct_name, $field_name),
size: ::core::mem::size_of::<*const $type>(),
@@ -206,7 +206,7 @@ macro_rules! vmstate_array_of_pointer {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), 0)
.as_bytes()
- .as_ptr() as *const ::core::ffi::c_char,
+ .as_ptr() as *const ::std::os::raw::c_char,
version_id: $version_id,
num: $num as _,
info: unsafe { $info },
@@ -231,7 +231,7 @@ macro_rules! vmstate_array_of_pointer_to_struct {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), 0)
.as_bytes()
- .as_ptr() as *const ::core::ffi::c_char,
+ .as_ptr() as *const ::std::os::raw::c_char,
version_id: $version_id,
num: $num as _,
vmsd: unsafe { $vmsd },
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 37c4dd44f81..c7089f0cf21 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -2,7 +2,7 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use core::ffi::CStr;
+use std::{ffi::CStr, os::raw::c_void};
use qemu_api::{
bindings::*,
@@ -64,11 +64,10 @@ impl ObjectImpl for DummyState {
}
impl Class for DummyClass {
- const CLASS_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
- > = Some(dummy_class_init);
+ const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)> =
+ Some(dummy_class_init);
const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
> = None;
}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 28/40] rust: introduce a c_str macro
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (26 preceding siblings ...)
2024-11-04 17:27 ` [PULL 27/40] rust: use std::os::raw instead of core::ffi Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 29/40] rust: silence unknown warnings for the sake of old compilers Paolo Bonzini
` (12 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
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>
---
rust/hw/char/pl011/src/device.rs | 5 ++-
rust/hw/char/pl011/src/device_class.rs | 18 ++++-----
rust/hw/char/pl011/src/lib.rs | 6 ++-
rust/qemu-api/meson.build | 4 ++
rust/qemu-api/src/c_str.rs | 53 ++++++++++++++++++++++++++
rust/qemu-api/src/lib.rs | 1 +
rust/qemu-api/src/vmstate.rs | 2 +-
rust/qemu-api/tests/tests.rs | 8 ++--
8 files changed, 78 insertions(+), 19 deletions(-)
create mode 100644 rust/qemu-api/src/c_str.rs
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 036757f7f3a..2d225d544de 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -10,6 +10,7 @@
use qemu_api::{
bindings::{self, *},
+ c_str,
definitions::ObjectImpl,
};
@@ -135,7 +136,7 @@ impl PL011State {
/// location/instance. All its fields are expected to hold unitialized
/// values with the sole exception of `parent_obj`.
unsafe fn init(&mut self) {
- const CLK_NAME: &CStr = c"clk";
+ const CLK_NAME: &CStr = c_str!("clk");
let dev = addr_of_mut!(*self).cast::<DeviceState>();
// SAFETY:
@@ -598,7 +599,7 @@ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
- qdev_prop_set_chr(dev, c"chardev".as_ptr(), chr);
+ qdev_prop_set_chr(dev, c_str!("chardev").as_ptr(), chr);
sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
sysbus_mmio_map(sysbus, 0, addr);
sysbus_connect_irq(sysbus, 0, irq);
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index 6a554ad7926..a707fde1384 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -2,14 +2,12 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use core::{
- ffi::{c_int, c_void},
- ptr::NonNull,
-};
+use core::ptr::NonNull;
+use std::os::raw::{c_int, c_void};
use qemu_api::{
- bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32,
- vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
+ bindings::*, c_str, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections,
+ vmstate_uint32, vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
};
use crate::device::{PL011State, PL011_FIFO_DEPTH};
@@ -24,7 +22,7 @@ extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
/// Migration subsection for [`PL011State`] clock.
pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
- name: c"pl011/clock".as_ptr(),
+ name: c_str!("pl011/clock").as_ptr(),
version_id: 1,
minimum_version_id: 1,
needed: Some(pl011_clock_needed),
@@ -48,7 +46,7 @@ extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
}
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
- name: c"pl011".as_ptr(),
+ name: c_str!("pl011").as_ptr(),
version_id: 2,
minimum_version_id: 2,
post_load: Some(pl011_post_load),
@@ -79,14 +77,14 @@ extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
qemu_api::declare_properties! {
PL011_PROPERTIES,
qemu_api::define_property!(
- c"chardev",
+ c_str!("chardev"),
PL011State,
char_backend,
unsafe { &qdev_prop_chr },
CharBackend
),
qemu_api::define_property!(
- c"migrate-clk",
+ c_str!("migrate-clk"),
PL011State,
migrate_clock,
unsafe { &qdev_prop_bool },
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
index 69e96d72854..cd0a49acb91 100644
--- a/rust/hw/char/pl011/src/lib.rs
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -42,12 +42,14 @@
extern crate bilge_impl;
extern crate qemu_api;
+use qemu_api::c_str;
+
pub mod device;
pub mod device_class;
pub mod memory_ops;
-pub const TYPE_PL011: &::std::ffi::CStr = c"pl011";
-pub const TYPE_PL011_LUMINARY: &::std::ffi::CStr = c"pl011_luminary";
+pub const TYPE_PL011: &::std::ffi::CStr = c_str!("pl011");
+pub const TYPE_PL011_LUMINARY: &::std::ffi::CStr = c_str!("pl011_luminary");
/// Offset of each register from the base memory address of the device.
///
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 3b849f7c413..c950b008d59 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -3,6 +3,7 @@ _qemu_api_rs = static_library(
structured_sources(
[
'src/lib.rs',
+ 'src/c_str.rs',
'src/definitions.rs',
'src/device_class.rs',
'src/vmstate.rs',
@@ -18,6 +19,9 @@ _qemu_api_rs = static_library(
],
)
+rust.test('rust-qemu-api-tests', _qemu_api_rs,
+ suite: ['unit', 'rust'])
+
qemu_api = declare_dependency(
link_with: _qemu_api_rs,
dependencies: qemu_api_macros,
diff --git a/rust/qemu-api/src/c_str.rs b/rust/qemu-api/src/c_str.rs
new file mode 100644
index 00000000000..4cd96da0b45
--- /dev/null
+++ b/rust/qemu-api/src/c_str.rs
@@ -0,0 +1,53 @@
+// Copyright 2024 Red Hat, Inc.
+// Author(s): Paolo Bonzini <pbonzini@redhat.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#[macro_export]
+/// Given a string constant _without_ embedded or trailing NULs, return
+/// a `CStr`.
+///
+/// Needed for compatibility with Rust <1.77.
+macro_rules! c_str {
+ ($str:expr) => {{
+ const STRING: &str = concat!($str, "\0");
+ const BYTES: &[u8] = STRING.as_bytes();
+
+ // "for" is not allowed in const context... oh well,
+ // everybody loves some lisp. This could be turned into
+ // a procedural macro if this is a problem; alternatively
+ // Rust 1.72 makes CStr::from_bytes_with_nul a const function.
+ const fn f(b: &[u8], i: usize) {
+ if i == b.len() - 1 {
+ } else if b[i] == 0 {
+ panic!("c_str argument contains NUL")
+ } else {
+ f(b, i + 1)
+ }
+ }
+ f(BYTES, 0);
+
+ // SAFETY: absence of NULs apart from the final byte was checked above
+ unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(BYTES) }
+ }};
+}
+
+#[cfg(test)]
+mod tests {
+ use std::ffi::CStr;
+
+ use crate::c_str;
+
+ #[test]
+ fn test_cstr_macro() {
+ let good = c_str!("🦀");
+ let good_bytes = b"\xf0\x9f\xa6\x80\0";
+ assert_eq!(good.to_bytes_with_nul(), good_bytes);
+ }
+
+ #[test]
+ fn test_cstr_macro_const() {
+ const GOOD: &CStr = c_str!("🦀");
+ const GOOD_BYTES: &[u8] = b"\xf0\x9f\xa6\x80\0";
+ assert_eq!(GOOD.to_bytes_with_nul(), GOOD_BYTES);
+ }
+}
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index ed840ee2f72..e6bd953e10b 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -29,6 +29,7 @@ unsafe impl Sync for bindings::VMStateDescription {}
unsafe impl Sync for bindings::VMStateField {}
unsafe impl Sync for bindings::VMStateInfo {}
+pub mod c_str;
pub mod definitions;
pub mod device_class;
pub mod vmstate;
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 4e06e40505f..9c252ce18ef 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -15,7 +15,7 @@
macro_rules! vmstate_unused_buffer {
($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
$crate::bindings::VMStateField {
- name: c"unused".as_ptr(),
+ name: c_str!("unused").as_ptr(),
err_hint: ::core::ptr::null(),
offset: 0,
size: $size,
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index c7089f0cf21..381ac84657b 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -6,7 +6,7 @@
use qemu_api::{
bindings::*,
- declare_properties, define_property,
+ c_str, declare_properties, define_property,
definitions::{Class, ObjectImpl},
device_class_init,
zeroable::Zeroable,
@@ -16,7 +16,7 @@
fn test_device_decl_macros() {
// Test that macros can compile.
pub static VMSTATE: VMStateDescription = VMStateDescription {
- name: c"name".as_ptr(),
+ name: c_str!("name").as_ptr(),
unmigratable: true,
..Zeroable::ZERO
};
@@ -36,7 +36,7 @@ pub struct DummyClass {
declare_properties! {
DUMMY_PROPERTIES,
define_property!(
- c"migrate-clk",
+ c_str!("migrate-clk"),
DummyState,
migrate_clock,
unsafe { &qdev_prop_bool },
@@ -55,7 +55,7 @@ pub struct DummyClass {
impl ObjectImpl for DummyState {
type Class = DummyClass;
const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
- const TYPE_NAME: &'static CStr = c"dummy";
+ const TYPE_NAME: &'static CStr = c_str!("dummy");
const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_DEVICE);
const ABSTRACT: bool = false;
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 29/40] rust: silence unknown warnings for the sake of old compilers
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (27 preceding siblings ...)
2024-11-04 17:27 ` [PULL 28/40] rust: introduce a c_str macro Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 30/40] rust: synchronize dependencies between subprojects and Cargo.lock Paolo Bonzini
` (11 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Occasionally, we may need to silence warnings and clippy lints that
were only introduced in newer Rust compiler versions. However, this
would fail when compiling with an older rustc:
error: unknown lint: `non_local_definitions`
--> rust/qemu-api/rust-qemu-api-tests.p/structured/offset_of.rs:79:17
So by default we need to block the unknown_lints warning. To avoid
misspelled lints or other similar issues, re-enable it in the CI job
that uses nightly rust.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 8 ++++++++
.gitlab-ci.d/buildtest.yml | 2 +-
meson_options.txt | 2 ++
scripts/meson-buildoptions.sh | 4 ++++
4 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index aa0b0fc5584..2f7e0550105 100644
--- a/meson.build
+++ b/meson.build
@@ -3341,6 +3341,14 @@ if have_rust and have_system
# Prohibit code that is forbidden in Rust 2024
rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
+ # Occasionally, we may need to silence warnings and clippy lints that
+ # were only introduced in newer Rust compiler versions. Do not croak
+ # in that case; a CI job with rust_strict_lints == true ensures that
+ # we do not have misspelled allow() attributes.
+ if not get_option('strict_rust_lints')
+ rustc_args += ['-A', 'unknown_lints']
+ endif
+
# Apart from procedural macros, our Rust executables will often link
# with C code, so include all the libraries that C code needs. This
# is safe; https://github.com/rust-lang/rust/pull/54675 says that
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
index 19ba5b9c818..aba65ff833a 100644
--- a/.gitlab-ci.d/buildtest.yml
+++ b/.gitlab-ci.d/buildtest.yml
@@ -128,7 +128,7 @@ build-system-fedora-rust-nightly:
job: amd64-fedora-rust-nightly-container
variables:
IMAGE: fedora-rust-nightly
- CONFIGURE_ARGS: --disable-docs --enable-rust
+ CONFIGURE_ARGS: --disable-docs --enable-rust --enable-strict-rust-lints
TARGETS: aarch64-softmmu
MAKE_CHECK_ARGS: check-build
allow_failure: true
diff --git a/meson_options.txt b/meson_options.txt
index 0ee4d7bb86b..e46199a3232 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -376,3 +376,5 @@ option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'], value
option('rust', type: 'feature', value: 'disabled',
description: 'Rust support')
+option('strict_rust_lints', type: 'boolean', value: false,
+ description: 'Enable stricter set of Rust warnings')
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 6d08605b771..e898b20307d 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -47,6 +47,8 @@ meson_options_help() {
printf "%s\n" ' getrandom()'
printf "%s\n" ' --enable-safe-stack SafeStack Stack Smash Protection (requires'
printf "%s\n" ' clang/llvm and coroutine backend ucontext)'
+ printf "%s\n" ' --enable-strict-rust-lints'
+ printf "%s\n" ' Enable stricter set of Rust warnings'
printf "%s\n" ' --enable-strip Strip targets on install'
printf "%s\n" ' --enable-tcg-interpreter TCG with bytecode interpreter (slow)'
printf "%s\n" ' --enable-trace-backends=CHOICES'
@@ -490,6 +492,8 @@ _meson_option_parse() {
--disable-spice-protocol) printf "%s" -Dspice_protocol=disabled ;;
--enable-stack-protector) printf "%s" -Dstack_protector=enabled ;;
--disable-stack-protector) printf "%s" -Dstack_protector=disabled ;;
+ --enable-strict-rust-lints) printf "%s" -Dstrict_rust_lints=true ;;
+ --disable-strict-rust-lints) printf "%s" -Dstrict_rust_lints=false ;;
--enable-strip) printf "%s" -Dstrip=true ;;
--disable-strip) printf "%s" -Dstrip=false ;;
--sysconfdir=*) quote_sh "-Dsysconfdir=$2" ;;
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 30/40] rust: synchronize dependencies between subprojects and Cargo.lock
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (28 preceding siblings ...)
2024-11-04 17:27 ` [PULL 29/40] rust: silence unknown warnings for the sake of old compilers Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 31/40] rust: create a cargo workspace Paolo Bonzini
` (10 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
The next commit will introduce a new build.rs dependency for rust/qemu-api,
version_check. Before adding it, ensure that all dependencies are
synchronized between the Meson- and cargo-based build systems.
Note that it's not clear whether in the long term we'll use Cargo for
anything; it seems that the three main uses (clippy, rustfmt, rustdoc)
can all be invoked manually---either via glue code in QEMU, or by
extending Meson to gain the relevant functionality. However, for
the time being we're stuck with Cargo so it should at least look at
the same code as the rest of the build system.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/pl011/Cargo.lock | 3 +++
rust/qemu-api-macros/Cargo.lock | 8 +++---
rust/qemu-api/Cargo.lock | 47 +++++++++++++++++++++++++++++++++
rust/qemu-api/Cargo.toml | 1 +
4 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/rust/hw/char/pl011/Cargo.lock b/rust/hw/char/pl011/Cargo.lock
index b58cebb186e..9f43b33e8b8 100644
--- a/rust/hw/char/pl011/Cargo.lock
+++ b/rust/hw/char/pl011/Cargo.lock
@@ -91,6 +91,9 @@ dependencies = [
[[package]]
name = "qemu_api"
version = "0.1.0"
+dependencies = [
+ "qemu_api_macros",
+]
[[package]]
name = "qemu_api_macros"
diff --git a/rust/qemu-api-macros/Cargo.lock b/rust/qemu-api-macros/Cargo.lock
index fdc0fce116c..73c334e7ce9 100644
--- a/rust/qemu-api-macros/Cargo.lock
+++ b/rust/qemu-api-macros/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
dependencies = [
"unicode-ident",
]
@@ -31,9 +31,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.72"
+version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
diff --git a/rust/qemu-api/Cargo.lock b/rust/qemu-api/Cargo.lock
index e9c51a243a8..e407911cdd1 100644
--- a/rust/qemu-api/Cargo.lock
+++ b/rust/qemu-api/Cargo.lock
@@ -2,6 +2,53 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "proc-macro2"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
+dependencies = [
+ "unicode-ident",
+]
+
[[package]]
name = "qemu_api"
version = "0.1.0"
+dependencies = [
+ "qemu_api_macros",
+]
+
+[[package]]
+name = "qemu_api_macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
index 3677def3fe2..db594c64083 100644
--- a/rust/qemu-api/Cargo.toml
+++ b/rust/qemu-api/Cargo.toml
@@ -14,6 +14,7 @@ keywords = []
categories = []
[dependencies]
+qemu_api_macros = { path = "../qemu-api-macros" }
[features]
default = []
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 31/40] rust: create a cargo workspace
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (29 preceding siblings ...)
2024-11-04 17:27 ` [PULL 30/40] rust: synchronize dependencies between subprojects and Cargo.lock Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 32/40] rust: introduce alternative implementation of offset_of! Paolo Bonzini
` (9 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Workspaces allows tracking dependencies for multiple crates at once,
by having a single Cargo.lock file at the top of the rust/ tree.
Because QEMU's Cargo.lock files have to be synchronized with the versions
of crates in subprojects/, using a workspace avoids the need to copy
over the Cargo.lock file when adding a new device (and thus a new crate)
under rust/hw/.
In addition, workspaces let cargo download and build dependencies just
once. While right now we have one leaf crate (hw/char/pl011), this
will not be the case once more devices are added.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/{hw/char/pl011 => }/Cargo.lock | 0
rust/Cargo.toml | 7 ++++
rust/hw/char/pl011/Cargo.toml | 3 --
rust/qemu-api-macros/Cargo.lock | 47 -------------------------
rust/qemu-api-macros/Cargo.toml | 3 --
rust/qemu-api/Cargo.lock | 54 -----------------------------
rust/qemu-api/Cargo.toml | 3 --
7 files changed, 7 insertions(+), 110 deletions(-)
rename rust/{hw/char/pl011 => }/Cargo.lock (100%)
create mode 100644 rust/Cargo.toml
delete mode 100644 rust/qemu-api-macros/Cargo.lock
delete mode 100644 rust/qemu-api/Cargo.lock
diff --git a/rust/hw/char/pl011/Cargo.lock b/rust/Cargo.lock
similarity index 100%
rename from rust/hw/char/pl011/Cargo.lock
rename to rust/Cargo.lock
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
new file mode 100644
index 00000000000..0c94d5037da
--- /dev/null
+++ b/rust/Cargo.toml
@@ -0,0 +1,7 @@
+[workspace]
+resolver = "2"
+members = [
+ "qemu-api-macros",
+ "qemu-api",
+ "hw/char/pl011",
+]
diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml
index b089e3dded6..a373906b9fb 100644
--- a/rust/hw/char/pl011/Cargo.toml
+++ b/rust/hw/char/pl011/Cargo.toml
@@ -21,6 +21,3 @@ bilge = { version = "0.2.0" }
bilge-impl = { version = "0.2.0" }
qemu_api = { path = "../../../qemu-api" }
qemu_api_macros = { path = "../../../qemu-api-macros" }
-
-# Do not include in any global workspace
-[workspace]
diff --git a/rust/qemu-api-macros/Cargo.lock b/rust/qemu-api-macros/Cargo.lock
deleted file mode 100644
index 73c334e7ce9..00000000000
--- a/rust/qemu-api-macros/Cargo.lock
+++ /dev/null
@@ -1,47 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.84"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "qemu_api_macros"
-version = "0.1.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.66"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml
index 144cc3650fa..f8d6d03609f 100644
--- a/rust/qemu-api-macros/Cargo.toml
+++ b/rust/qemu-api-macros/Cargo.toml
@@ -20,6 +20,3 @@ proc-macro = true
proc-macro2 = "1"
quote = "1"
syn = "2"
-
-# Do not include in any global workspace
-[workspace]
diff --git a/rust/qemu-api/Cargo.lock b/rust/qemu-api/Cargo.lock
deleted file mode 100644
index e407911cdd1..00000000000
--- a/rust/qemu-api/Cargo.lock
+++ /dev/null
@@ -1,54 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.84"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "qemu_api"
-version = "0.1.0"
-dependencies = [
- "qemu_api_macros",
-]
-
-[[package]]
-name = "qemu_api_macros"
-version = "0.1.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.66"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
index db594c64083..e092f61e8f3 100644
--- a/rust/qemu-api/Cargo.toml
+++ b/rust/qemu-api/Cargo.toml
@@ -20,8 +20,5 @@ qemu_api_macros = { path = "../qemu-api-macros" }
default = []
allocator = []
-# Do not include in any global workspace
-[workspace]
-
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] }
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 32/40] rust: introduce alternative implementation of offset_of!
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (30 preceding siblings ...)
2024-11-04 17:27 ` [PULL 31/40] rust: create a cargo workspace Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-07 11:28 ` Manos Pitsidianakis
2024-11-04 17:27 ` [PULL 33/40] rust: do not use MaybeUninit::zeroed() Paolo Bonzini
` (8 subsequent siblings)
40 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
From: Junjie Mao <junjie.mao@hotmail.com>
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>
---
rust/Cargo.lock | 1 +
rust/hw/char/pl011/src/device.rs | 2 +-
rust/qemu-api-macros/Cargo.toml | 2 +-
rust/qemu-api-macros/src/lib.rs | 75 +++++++-
rust/qemu-api/Cargo.toml | 6 +-
rust/qemu-api/build.rs | 9 +
rust/qemu-api/meson.build | 12 +-
rust/qemu-api/src/device_class.rs | 8 +-
rust/qemu-api/src/lib.rs | 4 +
rust/qemu-api/src/offset_of.rs | 161 ++++++++++++++++++
rust/qemu-api/src/vmstate.rs | 10 +-
rust/qemu-api/tests/tests.rs | 1 +
subprojects/packagefiles/syn-2-rs/meson.build | 1 +
13 files changed, 274 insertions(+), 18 deletions(-)
create mode 100644 rust/qemu-api/src/offset_of.rs
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 9f43b33e8b8..c0c6069247a 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -93,6 +93,7 @@ name = "qemu_api"
version = "0.1.0"
dependencies = [
"qemu_api_macros",
+ "version_check",
]
[[package]]
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 2d225d544de..bca727e37f0 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -55,7 +55,7 @@ impl DeviceId {
}
#[repr(C)]
-#[derive(Debug, qemu_api_macros::Object)]
+#[derive(Debug, qemu_api_macros::Object, qemu_api_macros::offsets)]
/// PL011 Device Model in QEMU
pub struct PL011State {
pub parent_obj: SysBusDevice,
diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml
index f8d6d03609f..a8f7377106b 100644
--- a/rust/qemu-api-macros/Cargo.toml
+++ b/rust/qemu-api-macros/Cargo.toml
@@ -19,4 +19,4 @@ proc-macro = true
[dependencies]
proc-macro2 = "1"
quote = "1"
-syn = "2"
+syn = { version = "2", features = ["extra-traits"] }
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index a4bc5d01ee8..cf99ac04b8f 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -3,8 +3,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use proc_macro::TokenStream;
-use quote::quote;
-use syn::{parse_macro_input, DeriveInput};
+use proc_macro2::Span;
+use quote::{quote, quote_spanned};
+use syn::{
+ parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Data, DeriveInput, Field,
+ Fields, Ident, Type, Visibility,
+};
+
+struct CompileError(String, Span);
+
+impl From<CompileError> for proc_macro2::TokenStream {
+ fn from(err: CompileError) -> Self {
+ let CompileError(msg, span) = err;
+ quote_spanned! { span => compile_error!(#msg); }
+ }
+}
+
+fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), CompileError> {
+ let expected = parse_quote! { #[repr(C)] };
+
+ if input.attrs.iter().any(|attr| attr == &expected) {
+ Ok(())
+ } else {
+ Err(CompileError(
+ format!("#[repr(C)] required for {}", msg),
+ input.ident.span(),
+ ))
+ }
+}
#[proc_macro_derive(Object)]
pub fn derive_object(input: TokenStream) -> TokenStream {
@@ -21,3 +47,48 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}
+
+fn get_fields(input: &DeriveInput) -> Result<&Punctuated<Field, Comma>, CompileError> {
+ if let Data::Struct(s) = &input.data {
+ if let Fields::Named(fs) = &s.fields {
+ Ok(&fs.named)
+ } else {
+ Err(CompileError(
+ "Cannot generate offsets for unnamed fields.".to_string(),
+ input.ident.span(),
+ ))
+ }
+ } else {
+ Err(CompileError(
+ "Cannot generate offsets for union or enum.".to_string(),
+ input.ident.span(),
+ ))
+ }
+}
+
+#[rustfmt::skip::macros(quote)]
+fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, CompileError> {
+ is_c_repr(&input, "#[derive(offsets)]")?;
+
+ let name = &input.ident;
+ let fields = get_fields(&input)?;
+ let field_names: Vec<&Ident> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
+ let field_types: Vec<&Type> = fields.iter().map(|f| &f.ty).collect();
+ let field_vis: Vec<&Visibility> = fields.iter().map(|f| &f.vis).collect();
+
+ Ok(quote! {
+ ::qemu_api::with_offsets! {
+ struct #name {
+ #(#field_vis #field_names: #field_types,)*
+ }
+ }
+ })
+}
+
+#[proc_macro_derive(offsets)]
+pub fn derive_offsets(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ let expanded = derive_offsets_or_error(input).unwrap_or_else(Into::into);
+
+ TokenStream::from(expanded)
+}
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
index e092f61e8f3..cc716d75d46 100644
--- a/rust/qemu-api/Cargo.toml
+++ b/rust/qemu-api/Cargo.toml
@@ -16,9 +16,13 @@ categories = []
[dependencies]
qemu_api_macros = { path = "../qemu-api-macros" }
+[build-dependencies]
+version_check = "~0.9"
+
[features]
default = []
allocator = []
[lints.rust]
-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] }
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)',
+ 'cfg(has_offset_of)'] }
diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs
index 419b154c2d2..20f8f718b90 100644
--- a/rust/qemu-api/build.rs
+++ b/rust/qemu-api/build.rs
@@ -4,6 +4,8 @@
use std::path::Path;
+use version_check as rustc;
+
fn main() {
if !Path::new("src/bindings.rs").exists() {
panic!(
@@ -11,4 +13,11 @@ fn main() {
(`ninja bindings.rs`) and copy them to src/bindings.rs, or build through meson."
);
}
+
+ // Check for available rustc features
+ if rustc::is_min_version("1.77.0").unwrap_or(false) {
+ println!("cargo:rustc-cfg=has_offset_of");
+ }
+
+ println!("cargo:rerun-if-changed=build.rs");
}
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index c950b008d59..6f637af7b1b 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -1,3 +1,9 @@
+_qemu_api_cfg = ['--cfg', 'MESON']
+# _qemu_api_cfg += ['--cfg', 'feature="allocator"']
+if rustc.version().version_compare('>=1.77.0')
+ _qemu_api_cfg += ['--cfg', 'has_offset_of']
+endif
+
_qemu_api_rs = static_library(
'qemu_api',
structured_sources(
@@ -6,6 +12,7 @@ _qemu_api_rs = static_library(
'src/c_str.rs',
'src/definitions.rs',
'src/device_class.rs',
+ 'src/offset_of.rs',
'src/vmstate.rs',
'src/zeroable.rs',
],
@@ -13,10 +20,7 @@ _qemu_api_rs = static_library(
),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
- rust_args: [
- '--cfg', 'MESON',
- # '--cfg', 'feature="allocator"',
- ],
+ rust_args: _qemu_api_cfg,
)
rust.test('rust-qemu-api-tests', _qemu_api_rs,
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index cb4573ca6ef..56608c7f7fc 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -23,23 +23,23 @@ macro_rules! device_class_init {
#[macro_export]
macro_rules! define_property {
- ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
+ ($name:expr, $state:ty, $field:ident, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
$crate::bindings::Property {
// use associated function syntax for type checking
name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
- offset: ::core::mem::offset_of!($state, $field) as isize,
+ offset: $crate::offset_of!($state, $field) as isize,
set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
..$crate::zeroable::Zeroable::ZERO
}
};
- ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
+ ($name:expr, $state:ty, $field:ident, $prop:expr, $type:expr$(,)*) => {
$crate::bindings::Property {
// use associated function syntax for type checking
name: ::std::ffi::CStr::as_ptr($name),
info: $prop,
- offset: ::core::mem::offset_of!($state, $field) as isize,
+ offset: $crate::offset_of!($state, $field) as isize,
set_default: false,
..$crate::zeroable::Zeroable::ZERO
}
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index e6bd953e10b..aa8d16ec94b 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -32,6 +32,7 @@ unsafe impl Sync for bindings::VMStateInfo {}
pub mod c_str;
pub mod definitions;
pub mod device_class;
+pub mod offset_of;
pub mod vmstate;
pub mod zeroable;
@@ -169,3 +170,6 @@ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
}
}
}
+
+#[cfg(has_offset_of)]
+pub use core::mem::offset_of;
diff --git a/rust/qemu-api/src/offset_of.rs b/rust/qemu-api/src/offset_of.rs
new file mode 100644
index 00000000000..075e98f986b
--- /dev/null
+++ b/rust/qemu-api/src/offset_of.rs
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: MIT
+
+/// This macro provides the same functionality as `core::mem::offset_of`,
+/// except that only one level of field access is supported. The declaration
+/// of the struct must be wrapped with `with_offsets! { }`.
+///
+/// It is needed because `offset_of!` was only stabilized in Rust 1.77.
+#[cfg(not(has_offset_of))]
+#[macro_export]
+macro_rules! offset_of {
+ ($Container:ty, $field:ident) => {
+ <$Container>::OFFSET_TO__.$field
+ };
+}
+
+/// A wrapper for struct declarations, that allows using `offset_of!` in
+/// versions of Rust prior to 1.77
+#[macro_export]
+macro_rules! with_offsets {
+ // This method to generate field offset constants comes from:
+ //
+ // https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df
+ //
+ // used under MIT license with permission of Yandros aka Daniel Henry-Mantilla
+ (
+ $(#[$struct_meta:meta])*
+ $struct_vis:vis
+ struct $StructName:ident {
+ $(
+ $(#[$field_meta:meta])*
+ $field_vis:vis
+ $field_name:ident : $field_ty:ty
+ ),*
+ $(,)?
+ }
+ ) => (
+ #[cfg(not(has_offset_of))]
+ const _: () = {
+ struct StructOffsetsHelper<T>(std::marker::PhantomData<T>);
+ const END_OF_PREV_FIELD: usize = 0;
+
+ // populate StructOffsetsHelper<T> with associated consts,
+ // one for each field
+ $crate::with_offsets! {
+ @struct $StructName
+ @names [ $($field_name)* ]
+ @tys [ $($field_ty ,)*]
+ }
+
+ // now turn StructOffsetsHelper<T>'s consts into a single struct,
+ // applying field visibility. This provides better error messages
+ // than if offset_of! used StructOffsetsHelper::<T> directly.
+ pub
+ struct StructOffsets {
+ $(
+ $field_vis
+ $field_name: usize,
+ )*
+ }
+ impl $StructName {
+ pub
+ const OFFSET_TO__: StructOffsets = StructOffsets {
+ $(
+ $field_name: StructOffsetsHelper::<$StructName>::$field_name,
+ )*
+ };
+ }
+ };
+ );
+
+ (
+ @struct $StructName:ident
+ @names []
+ @tys []
+ ) => ();
+
+ (
+ @struct $StructName:ident
+ @names [$field_name:ident $($other_names:tt)*]
+ @tys [$field_ty:ty , $($other_tys:tt)*]
+ ) => (
+ #[allow(non_local_definitions)]
+ #[allow(clippy::modulo_one)]
+ impl StructOffsetsHelper<$StructName> {
+ #[allow(nonstandard_style)]
+ const $field_name: usize = {
+ const ALIGN: usize = std::mem::align_of::<$field_ty>();
+ const TRAIL: usize = END_OF_PREV_FIELD % ALIGN;
+ END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL })
+ };
+ }
+ const _: () = {
+ const END_OF_PREV_FIELD: usize =
+ StructOffsetsHelper::<$StructName>::$field_name +
+ std::mem::size_of::<$field_ty>()
+ ;
+ $crate::with_offsets! {
+ @struct $StructName
+ @names [$($other_names)*]
+ @tys [$($other_tys)*]
+ }
+ };
+ );
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::offset_of;
+
+ #[repr(C)]
+ struct Foo {
+ a: u16,
+ b: u32,
+ c: u64,
+ d: u16,
+ }
+
+ #[repr(C)]
+ struct Bar {
+ pub a: u16,
+ pub b: u64,
+ c: Foo,
+ d: u64,
+ }
+
+ crate::with_offsets! {
+ #[repr(C)]
+ struct Bar {
+ pub a: u16,
+ pub b: u64,
+ c: Foo,
+ d: u64,
+ }
+ }
+
+ #[repr(C)]
+ pub struct Baz {
+ b: u32,
+ a: u8,
+ }
+ crate::with_offsets! {
+ #[repr(C)]
+ pub struct Baz {
+ b: u32,
+ a: u8,
+ }
+ }
+
+ #[test]
+ fn test_offset_of() {
+ const OFFSET_TO_C: usize = offset_of!(Bar, c);
+
+ assert_eq!(offset_of!(Bar, a), 0);
+ assert_eq!(offset_of!(Bar, b), 8);
+ assert_eq!(OFFSET_TO_C, 16);
+ assert_eq!(offset_of!(Bar, d), 40);
+
+ assert_eq!(offset_of!(Baz, b), 0);
+ assert_eq!(offset_of!(Baz, a), 4);
+ }
+}
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 9c252ce18ef..bedcf1e8f39 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -58,7 +58,7 @@ macro_rules! vmstate_single_test {
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
- offset: ::core::mem::offset_of!($struct_name, $field_name),
+ offset: $crate::offset_of!($struct_name, $field_name),
size: $size,
start: 0,
num: 0,
@@ -135,7 +135,7 @@ macro_rules! vmstate_array {
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
- offset: ::core::mem::offset_of!($struct_name, $field_name),
+ offset: $crate::offset_of!($struct_name, $field_name),
size: $size,
start: 0,
num: $length as _,
@@ -183,7 +183,7 @@ macro_rules! vmstate_struct_pointer_v {
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
err_hint: ::core::ptr::null(),
- offset: ::core::mem::offset_of!($struct_name, $field_name),
+ offset: $crate::offset_of!($struct_name, $field_name),
size: ::core::mem::size_of::<*const $type>(),
start: 0,
num: 0,
@@ -212,7 +212,7 @@ macro_rules! vmstate_array_of_pointer {
info: unsafe { $info },
size: ::core::mem::size_of::<*const $type>(),
flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
- offset: ::core::mem::offset_of!($struct_name, $field_name),
+ offset: $crate::offset_of!($struct_name, $field_name),
err_hint: ::core::ptr::null(),
start: 0,
num_offset: 0,
@@ -241,7 +241,7 @@ macro_rules! vmstate_array_of_pointer_to_struct {
| VMStateFlags::VMS_STRUCT.0
| VMStateFlags::VMS_ARRAY_OF_POINTER.0,
),
- offset: ::core::mem::offset_of!($struct_name, $field_name),
+ offset: $crate::offset_of!($struct_name, $field_name),
err_hint: ::core::ptr::null(),
start: 0,
num_offset: 0,
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 381ac84657b..7442f695646 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -21,6 +21,7 @@ fn test_device_decl_macros() {
..Zeroable::ZERO
};
+ #[derive(qemu_api_macros::offsets)]
#[repr(C)]
#[derive(qemu_api_macros::Object)]
pub struct DummyState {
diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build
index a53335f3092..9f56ce1c24d 100644
--- a/subprojects/packagefiles/syn-2-rs/meson.build
+++ b/subprojects/packagefiles/syn-2-rs/meson.build
@@ -24,6 +24,7 @@ _syn_rs = static_library(
'--cfg', 'feature="printing"',
'--cfg', 'feature="clone-impls"',
'--cfg', 'feature="proc-macro"',
+ '--cfg', 'feature="extra-traits"',
],
dependencies: [
quote_dep,
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 33/40] rust: do not use MaybeUninit::zeroed()
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (31 preceding siblings ...)
2024-11-04 17:27 ` [PULL 32/40] rust: introduce alternative implementation of offset_of! Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 34/40] rust: clean up detection of the language Paolo Bonzini
` (7 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
MaybeUninit::zeroed() is handy but is not available as a "const" function
until Rust 1.75.0.
Remove the default implementation of Zeroable::ZERO, and write by hand
the definitions for those types that need it. It may be possible to
add automatic implementation of the trait, via a procedural macro and/or
a trick similar to offset_of!, but do it the easy way for now.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/src/zeroable.rs | 91 +++++++++++++++++++++++++++++------
1 file changed, 77 insertions(+), 14 deletions(-)
diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs
index 45ec95c9f70..13cdb2ccba5 100644
--- a/rust/qemu-api/src/zeroable.rs
+++ b/rust/qemu-api/src/zeroable.rs
@@ -1,23 +1,86 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+use std::ptr;
+
/// Encapsulates the requirement that
-/// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause
-/// undefined behavior.
+/// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause undefined
+/// behavior. This trait in principle could be implemented as just:
+///
+/// ```
+/// const ZERO: Self = unsafe {
+/// ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init()
+/// },
+/// ```
+///
+/// The need for a manual implementation is only because `zeroed()` cannot
+/// be used as a `const fn` prior to Rust 1.75.0. Once we can assume a new
+/// enough version of the compiler, we could provide a `#[derive(Zeroable)]`
+/// macro to check at compile-time that all struct fields are Zeroable, and
+/// use the above blanket implementation of the `ZERO` constant.
///
/// # Safety
///
-/// Do not add this trait to a type unless all-zeroes is
-/// a valid value for the type. In particular, remember that raw
-/// pointers can be zero, but references and `NonNull<T>` cannot
-/// unless wrapped with `Option<>`.
+/// Because the implementation of `ZERO` is manual, it does not make
+/// any assumption on the safety of `zeroed()`. However, other users of the
+/// trait could use it that way. Do not add this trait to a type unless
+/// all-zeroes is a valid value for the type. In particular, remember that
+/// raw pointers can be zero, but references and `NonNull<T>` cannot
pub unsafe trait Zeroable: Default {
- /// SAFETY: If the trait was added to a type, then by definition
- /// this is safe.
- const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
+ const ZERO: Self;
}
-unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {}
-unsafe impl Zeroable for crate::bindings::Property {}
-unsafe impl Zeroable for crate::bindings::VMStateDescription {}
-unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {}
-unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {}
+unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {
+ const ZERO: Self = Self { i: 0 };
+}
+
+unsafe impl Zeroable for crate::bindings::Property {
+ const ZERO: Self = Self {
+ name: ptr::null(),
+ info: ptr::null(),
+ offset: 0,
+ bitnr: 0,
+ bitmask: 0,
+ set_default: false,
+ defval: Zeroable::ZERO,
+ arrayoffset: 0,
+ arrayinfo: ptr::null(),
+ arrayfieldsize: 0,
+ link_type: ptr::null(),
+ };
+}
+
+unsafe impl Zeroable for crate::bindings::VMStateDescription {
+ const ZERO: Self = Self {
+ name: ptr::null(),
+ unmigratable: false,
+ early_setup: false,
+ version_id: 0,
+ minimum_version_id: 0,
+ priority: crate::bindings::MigrationPriority::MIG_PRI_DEFAULT,
+ pre_load: None,
+ post_load: None,
+ pre_save: None,
+ post_save: None,
+ needed: None,
+ dev_unplug_pending: None,
+ fields: ptr::null(),
+ subsections: ptr::null(),
+ };
+}
+
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {
+ const ZERO: Self = Self {
+ min_access_size: 0,
+ max_access_size: 0,
+ unaligned: false,
+ accepts: None,
+ };
+}
+
+unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {
+ const ZERO: Self = Self {
+ min_access_size: 0,
+ max_access_size: 0,
+ unaligned: false,
+ };
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 34/40] rust: clean up detection of the language
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (32 preceding siblings ...)
2024-11-04 17:27 ` [PULL 33/40] rust: do not use MaybeUninit::zeroed() Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 35/40] rust: allow version 1.63.0 of rustc Paolo Bonzini
` (6 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Disable the detection code altogether if have_system == false.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 42 ++++++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/meson.build b/meson.build
index 2f7e0550105..eb5660a0836 100644
--- a/meson.build
+++ b/meson.build
@@ -53,6 +53,17 @@ cpu = host_machine.cpu_family()
target_dirs = config_host['TARGET_DIRS'].split()
+# type of binaries to build
+have_linux_user = false
+have_bsd_user = false
+have_system = false
+foreach target : target_dirs
+ have_linux_user = have_linux_user or target.endswith('linux-user')
+ have_bsd_user = have_bsd_user or target.endswith('bsd-user')
+ have_system = have_system or target.endswith('-softmmu')
+endforeach
+have_user = have_linux_user or have_bsd_user
+
############
# Programs #
############
@@ -71,11 +82,13 @@ if host_os == 'darwin' and \
all_languages += ['objc']
objc = meson.get_compiler('objc')
endif
-have_rust = false
-if not get_option('rust').disabled() and add_languages('rust', required: get_option('rust'), native: false) \
- and add_languages('rust', required: get_option('rust'), native: true)
+
+have_rust = add_languages('rust', native: false,
+ required: get_option('rust').disable_auto_if(not have_system))
+have_rust = have_rust and add_languages('rust', native: true,
+ required: get_option('rust').disable_auto_if(not have_system))
+if have_rust
rustc = meson.get_compiler('rust')
- have_rust = true
if rustc.version().version_compare('<1.80.0')
if get_option('rust').enabled()
error('rustc version ' + rustc.version() + ' is unsupported: Please upgrade to at least 1.80.0')
@@ -186,17 +199,6 @@ have_vhost_net_vdpa = have_vhost_vdpa and get_option('vhost_net').allowed()
have_vhost_net_kernel = have_vhost_kernel and get_option('vhost_net').allowed()
have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_vdpa
-# type of binaries to build
-have_linux_user = false
-have_bsd_user = false
-have_system = false
-foreach target : target_dirs
- have_linux_user = have_linux_user or target.endswith('linux-user')
- have_bsd_user = have_bsd_user or target.endswith('bsd-user')
- have_system = have_system or target.endswith('-softmmu')
-endforeach
-have_user = have_linux_user or have_bsd_user
-
have_tools = get_option('tools') \
.disable_auto_if(not have_system) \
.allowed()
@@ -3331,7 +3333,7 @@ endif
genh += configure_file(output: 'config-host.h', configuration: config_host_data)
-if have_rust and have_system
+if have_rust
rustc_args = run_command(
find_program('scripts/rust/rustc_args.py'),
'--config-headers', meson.project_build_root() / 'config-host.h',
@@ -3951,7 +3953,7 @@ common_all = static_library('common',
implicit_include_directories: false,
dependencies: common_ss.all_dependencies())
-if have_rust and have_system
+if have_rust
bindgen_args = [
'--disable-header-comment',
'--raw-line', '// @generated',
@@ -4105,7 +4107,7 @@ foreach target : target_dirs
arch_srcs += target_specific.sources()
arch_deps += target_specific.dependencies()
- if have_rust and have_system
+ if have_rust and target_type == 'system'
target_rust = rust_devices_ss.apply(config_target, strict: false)
crates = []
foreach dep : target_rust.dependencies()
@@ -4467,9 +4469,9 @@ else
endif
summary_info += {'Rust support': have_rust}
if have_rust
- summary_info += {'rustc version': rustc.version()}
- summary_info += {'rustc': ' '.join(rustc.cmd_array())}
summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']}
+ summary_info += {'rustc': ' '.join(rustc.cmd_array())}
+ summary_info += {'rustc version': rustc.version()}
endif
option_cflags = (get_option('debug') ? ['-g'] : [])
if get_option('optimization') != 'plain'
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 35/40] rust: allow version 1.63.0 of rustc
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (33 preceding siblings ...)
2024-11-04 17:27 ` [PULL 34/40] rust: clean up detection of the language Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 36/40] rust: do not use --generate-cstr Paolo Bonzini
` (5 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
All constructs introduced by newer versions of Rust have been removed.
Apart from Debian 12, all other supported Linux distributions have
rustc 1.75.0 or newer. This means that they only lack c"" literals
and stable offset_of!.
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index eb5660a0836..95b612e0b77 100644
--- a/meson.build
+++ b/meson.build
@@ -89,11 +89,12 @@ have_rust = have_rust and add_languages('rust', native: true,
required: get_option('rust').disable_auto_if(not have_system))
if have_rust
rustc = meson.get_compiler('rust')
- if rustc.version().version_compare('<1.80.0')
+ if rustc.version().version_compare('<1.63.0')
if get_option('rust').enabled()
- error('rustc version ' + rustc.version() + ' is unsupported: Please upgrade to at least 1.80.0')
+ error('rustc version ' + rustc.version() + ' is unsupported. Please upgrade to at least 1.63.0')
else
- warning('rustc version ' + rustc.version() + ' is unsupported: Disabling Rust compilation. Please upgrade to at least 1.80.0 to use Rust.')
+ warning('rustc version ' + rustc.version() + ' is unsupported, disabling Rust compilation.')
+ message('Please upgrade to at least 1.63.0 to use Rust.')
have_rust = false
endif
endif
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 36/40] rust: do not use --generate-cstr
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (34 preceding siblings ...)
2024-11-04 17:27 ` [PULL 35/40] rust: allow version 1.63.0 of rustc Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 37/40] rust: allow older version of bindgen Paolo Bonzini
` (4 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
--generate-cstr is a good idea and generally the right thing to do,
but it is not available in Debian 12 and Ubuntu 22.04. Work around
the absence.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 4 +++-
rust/hw/char/pl011/src/device.rs | 1 +
rust/qemu-api/src/device_class.rs | 10 ++++++++++
rust/qemu-api/tests/tests.rs | 4 ++--
4 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index 95b612e0b77..07f7e5f8f64 100644
--- a/meson.build
+++ b/meson.build
@@ -3955,13 +3955,15 @@ common_all = static_library('common',
dependencies: common_ss.all_dependencies())
if have_rust
+ # We would like to use --generate-cstr, but it is only available
+ # starting with bindgen 0.66.0. The oldest supported versions
+ # are in Ubuntu 22.04 (0.59.1) and Debian 12 (0.60.1).
bindgen_args = [
'--disable-header-comment',
'--raw-line', '// @generated',
'--ctypes-prefix', 'std::os::raw',
'--formatter', 'rustfmt',
'--generate-block',
- '--generate-cstr',
'--impl-debug',
'--merge-extern-blocks',
'--no-doc-comments',
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index bca727e37f0..2a85960b81f 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -12,6 +12,7 @@
bindings::{self, *},
c_str,
definitions::ObjectImpl,
+ device_class::TYPE_SYS_BUS_DEVICE,
};
use crate::{
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index 56608c7f7fc..0ba798d3e3c 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -2,6 +2,10 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
+use std::ffi::CStr;
+
+use crate::bindings;
+
#[macro_export]
macro_rules! device_class_init {
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
@@ -62,3 +66,9 @@ macro_rules! declare_properties {
];
};
}
+
+// workaround until we can use --generate-cstr in bindgen.
+pub const TYPE_DEVICE: &CStr =
+ unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
+pub const TYPE_SYS_BUS_DEVICE: &CStr =
+ unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) };
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 7442f695646..43a4827de12 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -8,7 +8,7 @@
bindings::*,
c_str, declare_properties, define_property,
definitions::{Class, ObjectImpl},
- device_class_init,
+ device_class, device_class_init,
zeroable::Zeroable,
};
@@ -57,7 +57,7 @@ impl ObjectImpl for DummyState {
type Class = DummyClass;
const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
const TYPE_NAME: &'static CStr = c_str!("dummy");
- const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_DEVICE);
+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(device_class::TYPE_DEVICE);
const ABSTRACT: bool = false;
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 37/40] rust: allow older version of bindgen
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (35 preceding siblings ...)
2024-11-04 17:27 ` [PULL 36/40] rust: do not use --generate-cstr Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 38/40] rust: make rustfmt optional Paolo Bonzini
` (3 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Cope with the old version that is provided in Debian 12.
--size_t-is-usize is needed on bindgen <0.61.0, and it was removed in
bindgen 0.65.0, so check for it in meson.build.
--merge-extern-blocks was added in 0.61.0.
--formatter rustfmt was added in 0.65.0 and is the default, so remove it.
Apart from Debian 12 and Ubuntu 22.04, all other supported distros have
version 0.66.x of bindgen or newer (or do not have bindgen at all).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
docs/about/build-platforms.rst | 12 ++++++++++++
meson.build | 29 +++++++++++++++++++++++++----
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst
index 8fd7da140a3..ff56091078e 100644
--- a/docs/about/build-platforms.rst
+++ b/docs/about/build-platforms.rst
@@ -107,6 +107,18 @@ Python build dependencies
required, it may be necessary to fetch python modules from the Python
Package Index (PyPI) via ``pip``, in order to build QEMU.
+Rust build dependencies
+ QEMU is generally conservative in adding new Rust dependencies, and all
+ of them are included in the distributed tarballs. One exception is the
+ bindgen tool, which is too big to package and distribute. The minimum
+ supported version of bindgen is 0.60.x. For distributions that do not
+ include bindgen or have an older version, it is recommended to install
+ a newer version using ``cargo install bindgen-cli``.
+
+ Developers may want to use Cargo-based tools in the QEMU source tree;
+ this requires Cargo 1.74.0. Note that Cargo is not required in order
+ to build QEMU.
+
Optional build dependencies
Build components whose absence does not affect the ability to build
QEMU may not be available in distros, or may be too old for QEMU's
diff --git a/meson.build b/meson.build
index 07f7e5f8f64..fffdeef8c80 100644
--- a/meson.build
+++ b/meson.build
@@ -100,6 +100,21 @@ if have_rust
endif
endif
+bindgen = find_program('bindgen', required: get_option('rust').disable_auto_if(not have_rust))
+if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
+ if get_option('rust').enabled()
+ error('bindgen version ' + bindgen.version() + ' is unsupported. You can install a new version with "cargo install bindgen-cli"')
+ else
+ if bindgen.found()
+ warning('bindgen version ' + bindgen.version() + ' is unsupported, disabling Rust compilation.')
+ else
+ warning('bindgen not found, disabling Rust compilation.')
+ endif
+ message('To use Rust you can install a new version with "cargo install bindgen-cli"')
+ have_rust = false
+ endif
+endif
+
dtrace = not_found
stap = not_found
if 'dtrace' in get_option('trace_backends')
@@ -3957,15 +3972,13 @@ common_all = static_library('common',
if have_rust
# We would like to use --generate-cstr, but it is only available
# starting with bindgen 0.66.0. The oldest supported versions
- # are in Ubuntu 22.04 (0.59.1) and Debian 12 (0.60.1).
+ # is 0.60.x (Debian 12 has 0.60.1) which introduces --allowlist-file.
bindgen_args = [
'--disable-header-comment',
'--raw-line', '// @generated',
'--ctypes-prefix', 'std::os::raw',
- '--formatter', 'rustfmt',
'--generate-block',
'--impl-debug',
- '--merge-extern-blocks',
'--no-doc-comments',
'--with-derive-default',
'--no-layout-tests',
@@ -3974,6 +3987,12 @@ if have_rust
'--allowlist-file', meson.project_source_root() + '/.*',
'--allowlist-file', meson.project_build_root() + '/.*'
]
+ if bindgen.version().version_compare('<0.61.0')
+ # default in 0.61+
+ bindgen_args += ['--size_t-is-usize']
+ else
+ bindgen_args += ['--merge-extern-blocks']
+ endif
c_enums = [
'DeviceCategory',
'GpioPolarity',
@@ -4009,7 +4028,7 @@ if have_rust
dependencies: common_ss.all_dependencies(),
output: 'bindings.rs',
include_directories: include_directories('.', 'include'),
- bindgen_version: ['>=0.69.4'],
+ bindgen_version: ['>=0.60.0'],
args: bindgen_args,
)
subdir('rust')
@@ -4475,6 +4494,8 @@ if have_rust
summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']}
summary_info += {'rustc': ' '.join(rustc.cmd_array())}
summary_info += {'rustc version': rustc.version()}
+ summary_info += {'bindgen': bindgen.full_path()}
+ summary_info += {'bindgen version': bindgen.version()}
endif
option_cflags = (get_option('debug') ? ['-g'] : [])
if get_option('optimization') != 'plain'
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 38/40] rust: make rustfmt optional
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (36 preceding siblings ...)
2024-11-04 17:27 ` [PULL 37/40] rust: allow older version of bindgen Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 39/40] dockerfiles: install bindgen from cargo on Ubuntu 22.04 Paolo Bonzini
` (2 subsequent siblings)
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
meson.build | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/meson.build b/meson.build
index fffdeef8c80..a0ae56c9625 100644
--- a/meson.build
+++ b/meson.build
@@ -115,6 +115,10 @@ if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
endif
endif
+if have_rust
+ rustfmt = find_program('rustfmt', required: false)
+endif
+
dtrace = not_found
stap = not_found
if 'dtrace' in get_option('trace_backends')
@@ -3987,6 +3991,13 @@ if have_rust
'--allowlist-file', meson.project_source_root() + '/.*',
'--allowlist-file', meson.project_build_root() + '/.*'
]
+ if not rustfmt.found()
+ if bindgen.version().version_compare('<0.65.0')
+ bindgen_args += ['--no-rustfmt-bindings']
+ else
+ bindgen_args += ['--formatter', 'none']
+ endif
+ endif
if bindgen.version().version_compare('<0.61.0')
# default in 0.61+
bindgen_args += ['--size_t-is-usize']
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 39/40] dockerfiles: install bindgen from cargo on Ubuntu 22.04
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (37 preceding siblings ...)
2024-11-04 17:27 ` [PULL 38/40] rust: make rustfmt optional Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-04 17:27 ` [PULL 40/40] ci: enable rust in the Debian and Ubuntu system build job Paolo Bonzini
2024-11-06 13:10 ` [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Peter Maydell
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Because Ubuntu 22.04 has a very old version of bindgen, that
does not have the important option --allowlist-file, it will
not be able to use --enable-rust out of the box. Instead,
install the latest version of bindgen-cli via "cargo install"
in the container, following QEMU's own documentation.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml | 1 -
scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml | 1 -
tests/docker/dockerfiles/ubuntu2204.docker | 6 +++++-
tests/lcitool/mappings.yml | 4 ++++
tests/lcitool/refresh | 11 ++++++++++-
5 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
index dd89ba1b3a7..31078f96462 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
@@ -7,7 +7,6 @@
packages:
- bash
- bc
- - bindgen
- bison
- bsdextrautils
- bzip2
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
index 74f14d8d0fe..fdd50d03e88 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
@@ -7,7 +7,6 @@
packages:
- bash
- bc
- - bindgen
- bison
- bsdextrautils
- bzip2
diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker
index ce3aa39d4f3..5f8a811788a 100644
--- a/tests/docker/dockerfiles/ubuntu2204.docker
+++ b/tests/docker/dockerfiles/ubuntu2204.docker
@@ -13,7 +13,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
eatmydata apt-get install --no-install-recommends -y \
bash \
bc \
- bindgen \
bison \
bsdextrautils \
bzip2 \
@@ -149,6 +148,11 @@ ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
ENV NINJA "/usr/bin/ninja"
ENV PYTHON "/usr/bin/python3"
+ENV CARGO_HOME=/usr/local/cargo
+ENV PATH=$CARGO_HOME/bin:$PATH
+RUN DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends cargo
+RUN cargo install bindgen-cli
# As a final step configure the user (if env is defined)
ARG USER
ARG UID
diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml
index 9c5ac87c1c2..c90b23a00f1 100644
--- a/tests/lcitool/mappings.yml
+++ b/tests/lcitool/mappings.yml
@@ -1,4 +1,8 @@
mappings:
+ # Too old on Ubuntu 22.04; we install it from cargo instead
+ bindgen:
+ Ubuntu2204:
+
flake8:
OpenSUSELeap15:
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index 0f16f4d525c..a46cbbdca41 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -137,6 +137,14 @@ fedora_rustup_nightly_extras = [
'RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli\n',
]
+ubuntu2204_bindgen_extras = [
+ "ENV CARGO_HOME=/usr/local/cargo\n",
+ 'ENV PATH=$CARGO_HOME/bin:$PATH\n',
+ "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n",
+ " apt install -y --no-install-recommends cargo\n",
+ 'RUN cargo install bindgen-cli\n',
+]
+
def cross_build(prefix, targets):
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
targets = "ENV DEF_TARGET_LIST %s\n" % (targets)
@@ -157,7 +165,8 @@ try:
trailer="".join(debian12_extras))
generate_dockerfile("fedora", "fedora-40")
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
- generate_dockerfile("ubuntu2204", "ubuntu-2204")
+ generate_dockerfile("ubuntu2204", "ubuntu-2204",
+ trailer="".join(ubuntu2204_bindgen_extras))
#
# Non-fatal Rust-enabled build
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PULL 40/40] ci: enable rust in the Debian and Ubuntu system build job
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (38 preceding siblings ...)
2024-11-04 17:27 ` [PULL 39/40] dockerfiles: install bindgen from cargo on Ubuntu 22.04 Paolo Bonzini
@ 2024-11-04 17:27 ` Paolo Bonzini
2024-11-06 13:10 ` [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Peter Maydell
40 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-04 17:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
We have fixed all incompatibilities with older versions of rustc
and bindgen. Enable Rust on Debian to check that the minimum
supported version of Rust is indeed 1.63.0, and 0.60.x for bindgen.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
.gitlab-ci.d/buildtest.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
index aba65ff833a..8deaf9627cb 100644
--- a/.gitlab-ci.d/buildtest.yml
+++ b/.gitlab-ci.d/buildtest.yml
@@ -40,7 +40,7 @@ build-system-ubuntu:
job: amd64-ubuntu2204-container
variables:
IMAGE: ubuntu2204
- CONFIGURE_ARGS: --enable-docs
+ CONFIGURE_ARGS: --enable-docs --enable-rust
TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
@@ -71,7 +71,7 @@ build-system-debian:
job: amd64-debian-container
variables:
IMAGE: debian
- CONFIGURE_ARGS: --with-coroutine=sigaltstack
+ CONFIGURE_ARGS: --with-coroutine=sigaltstack --enable-rust
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4-softmmu
sparc-softmmu xtensa-softmmu
MAKE_CHECK_ARGS: check-build
--
2.47.0
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PULL 00/40] Rust changes for QEMU 9.2 soft freeze
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
` (39 preceding siblings ...)
2024-11-04 17:27 ` [PULL 40/40] ci: enable rust in the Debian and Ubuntu system build job Paolo Bonzini
@ 2024-11-06 13:10 ` Peter Maydell
2024-11-06 13:14 ` Paolo Bonzini
40 siblings, 1 reply; 52+ messages in thread
From: Peter Maydell @ 2024-11-06 13:10 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Alex Bennée, Junjie Mao, Kevin Wolf,
Manos Pitsidianakis, Pierrick Bouvier, Zhao Liu
On Mon, 4 Nov 2024 at 17:35, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> The following changes since commit 15195de6a93438be99fdf9a90992c4228527130d:
>
> ci: enable rust in the Fedora system build job (2024-10-30 16:30:56 +0100)
>
> are available in the Git repository at:
>
> https://gitlab.com/bonzini/qemu.git tags/for-upstream-rust
>
> for you to fetch changes up to d20feaa9a5af597bd20630d041e5dc7808612be1:
>
> ci: enable rust in the Debian and Ubuntu system build job (2024-10-31 18:39:52 +0100)
>
> ----------------------------------------------------------------
> * rust: cleanups
> * rust: integration tests
> * rust/pl011: add support for migration
> * rust/pl011: add TYPE_PL011_LUMINARY device
> * rust: add support for older compilers and bindgen
> * rust: enable rust in the Debian, Fedora and Ubuntu system build job
>
> ----------------------------------------------------------------
This probably isn't something worth not merging this for, but I
noticed while testing (via vm-build-openbsd) that Meson complains:
Compiler for language rust for the host machine not found.
Program bindgen skipped: feature rust disabled
../meson.build:111: WARNING: bindgen not found, disabling Rust compilation.
Message: To use Rust you can install a new version with "cargo install
bindgen-cli"
Rust is still disabled-by-default, so why is meson probing for bindgen?
It would be nice if we could avoid printing WARNING messages for
the normal case.
(I'm continuing with the CI test run.)
thanks
-- PMM
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 00/40] Rust changes for QEMU 9.2 soft freeze
2024-11-06 13:10 ` [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Peter Maydell
@ 2024-11-06 13:14 ` Paolo Bonzini
2024-11-06 14:59 ` Peter Maydell
0 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-06 13:14 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Alex Bennée, Junjie Mao, Kevin Wolf,
Manos Pitsidianakis, Pierrick Bouvier, Zhao Liu
On Wed, Nov 6, 2024 at 2:10 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Mon, 4 Nov 2024 at 17:35, Paolo Bonzini <pbonzini@redhat.com> wrote:
> >
> > The following changes since commit 15195de6a93438be99fdf9a90992c4228527130d:
> >
> > ci: enable rust in the Fedora system build job (2024-10-30 16:30:56 +0100)
> >
> > are available in the Git repository at:
> >
> > https://gitlab.com/bonzini/qemu.git tags/for-upstream-rust
> >
> > for you to fetch changes up to d20feaa9a5af597bd20630d041e5dc7808612be1:
> >
> > ci: enable rust in the Debian and Ubuntu system build job (2024-10-31 18:39:52 +0100)
> >
> > ----------------------------------------------------------------
> > * rust: cleanups
> > * rust: integration tests
> > * rust/pl011: add support for migration
> > * rust/pl011: add TYPE_PL011_LUMINARY device
> > * rust: add support for older compilers and bindgen
> > * rust: enable rust in the Debian, Fedora and Ubuntu system build job
> >
> > ----------------------------------------------------------------
>
> This probably isn't something worth not merging this for, but I
> noticed while testing (via vm-build-openbsd) that Meson complains:
>
> Compiler for language rust for the host machine not found.
> Program bindgen skipped: feature rust disabled
> ../meson.build:111: WARNING: bindgen not found, disabling Rust compilation.
> Message: To use Rust you can install a new version with "cargo install
> bindgen-cli"
>
> Rust is still disabled-by-default, so why is meson probing for bindgen?
It's not probing it ("Program bindgen skipped"), but I was a bit too
happy about printing warnings. This line:
if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
should simply have had an "if not have_rust", or something like that.
If you want I can resend. I know that Linaro people are in Dublin, so
whatever is easiest for you.
Paolo
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 00/40] Rust changes for QEMU 9.2 soft freeze
2024-11-06 13:14 ` Paolo Bonzini
@ 2024-11-06 14:59 ` Peter Maydell
2024-11-06 16:27 ` Paolo Bonzini
0 siblings, 1 reply; 52+ messages in thread
From: Peter Maydell @ 2024-11-06 14:59 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Alex Bennée, Junjie Mao, Kevin Wolf,
Manos Pitsidianakis, Pierrick Bouvier, Zhao Liu
On Wed, 6 Nov 2024 at 13:14, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On Wed, Nov 6, 2024 at 2:10 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Mon, 4 Nov 2024 at 17:35, Paolo Bonzini <pbonzini@redhat.com> wrote:
> > >
> > > The following changes since commit 15195de6a93438be99fdf9a90992c4228527130d:
> > >
> > > ci: enable rust in the Fedora system build job (2024-10-30 16:30:56 +0100)
> > >
> > > are available in the Git repository at:
> > >
> > > https://gitlab.com/bonzini/qemu.git tags/for-upstream-rust
> > >
> > > for you to fetch changes up to d20feaa9a5af597bd20630d041e5dc7808612be1:
> > >
> > > ci: enable rust in the Debian and Ubuntu system build job (2024-10-31 18:39:52 +0100)
> > >
> > > ----------------------------------------------------------------
> > > * rust: cleanups
> > > * rust: integration tests
> > > * rust/pl011: add support for migration
> > > * rust/pl011: add TYPE_PL011_LUMINARY device
> > > * rust: add support for older compilers and bindgen
> > > * rust: enable rust in the Debian, Fedora and Ubuntu system build job
> > >
> > > ----------------------------------------------------------------
> >
> > This probably isn't something worth not merging this for, but I
> > noticed while testing (via vm-build-openbsd) that Meson complains:
> >
> > Compiler for language rust for the host machine not found.
> > Program bindgen skipped: feature rust disabled
> > ../meson.build:111: WARNING: bindgen not found, disabling Rust compilation.
> > Message: To use Rust you can install a new version with "cargo install
> > bindgen-cli"
> >
> > Rust is still disabled-by-default, so why is meson probing for bindgen?
>
> It's not probing it ("Program bindgen skipped"), but I was a bit too
> happy about printing warnings. This line:
>
> if not bindgen.found() or bindgen.version().version_compare('<0.60.0')
>
> should simply have had an "if not have_rust", or something like that.
>
> If you want I can resend. I know that Linaro people are in Dublin, so
> whatever is easiest for you.
(I'm not in Dublin, as it happens.) I don't think this needs
to be fixed in this pullreq; it's fine to send a patch to
fix this cosmetic issue and we'll apply it sometime during freeze.
However, this does seem to be causing the functional-tests to timeout
on the CI job that now enables Rust:
https://gitlab.com/qemu-project/qemu/-/jobs/8284623145
https://gitlab.com/qemu-project/qemu/-/jobs/8283637798
both fail with
01-tests/avocado/boot_linux_console.py:BootLinuxConsole.test_arm_virt:
INTERRUPTED
13-tests/avocado/replay_kernel.py:ReplayKernelNormal.test_arm_virt: INTERRUPTED
15-tests/avocado/replay_kernel.py:ReplayKernelNormal.test_arm_vexpressa9:
INTERRUPTED
(which I suspect will turn out to be "all the functional tests that
use a pl011").
Could you have a look, please?
thanks
-- PMM
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 00/40] Rust changes for QEMU 9.2 soft freeze
2024-11-06 14:59 ` Peter Maydell
@ 2024-11-06 16:27 ` Paolo Bonzini
0 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-06 16:27 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Alex Bennée, Junjie Mao, Kevin Wolf,
Manos Pitsidianakis, Pierrick Bouvier, Zhao Liu
On Wed, Nov 6, 2024 at 4:00 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> However, this does seem to be causing the functional-tests to timeout
> on the CI job that now enables Rust:
>
> https://gitlab.com/qemu-project/qemu/-/jobs/8284623145
> https://gitlab.com/qemu-project/qemu/-/jobs/8283637798
>
> both fail with
>
> 01-tests/avocado/boot_linux_console.py:BootLinuxConsole.test_arm_virt:
> INTERRUPTED
> 13-tests/avocado/replay_kernel.py:ReplayKernelNormal.test_arm_virt: INTERRUPTED
> 15-tests/avocado/replay_kernel.py:ReplayKernelNormal.test_arm_vexpressa9:
> INTERRUPTED
>
> (which I suspect will turn out to be "all the functional tests that
> use a pl011").
>
> Could you have a look, please?
Drat, I'll just drop the patch that enables Rust in CI. Not really in
the mood of debugging device code.
Paolo
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 32/40] rust: introduce alternative implementation of offset_of!
2024-11-04 17:27 ` [PULL 32/40] rust: introduce alternative implementation of offset_of! Paolo Bonzini
@ 2024-11-07 11:28 ` Manos Pitsidianakis
2024-11-07 11:31 ` Paolo Bonzini
0 siblings, 1 reply; 52+ messages in thread
From: Manos Pitsidianakis @ 2024-11-07 11:28 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel
Cc: Alex Benné e, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
On Mon, 04 Nov 2024 17:27, Paolo Bonzini <pbonzini@redhat.com> wrote:
>From: Junjie Mao <junjie.mao@hotmail.com>
>
>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>
>---
> rust/Cargo.lock | 1 +
> rust/hw/char/pl011/src/device.rs | 2 +-
> rust/qemu-api-macros/Cargo.toml | 2 +-
> rust/qemu-api-macros/src/lib.rs | 75 +++++++-
> rust/qemu-api/Cargo.toml | 6 +-
> rust/qemu-api/build.rs | 9 +
> rust/qemu-api/meson.build | 12 +-
> rust/qemu-api/src/device_class.rs | 8 +-
> rust/qemu-api/src/lib.rs | 4 +
> rust/qemu-api/src/offset_of.rs | 161 ++++++++++++++++++
> rust/qemu-api/src/vmstate.rs | 10 +-
> rust/qemu-api/tests/tests.rs | 1 +
> subprojects/packagefiles/syn-2-rs/meson.build | 1 +
> 13 files changed, 274 insertions(+), 18 deletions(-)
> create mode 100644 rust/qemu-api/src/offset_of.rs
>
>diff --git a/rust/Cargo.lock b/rust/Cargo.lock
>index 9f43b33e8b8..c0c6069247a 100644
>--- a/rust/Cargo.lock
>+++ b/rust/Cargo.lock
>@@ -93,6 +93,7 @@ name = "qemu_api"
> version = "0.1.0"
> dependencies = [
> "qemu_api_macros",
>+ "version_check",
> ]
>
> [[package]]
>diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
>index 2d225d544de..bca727e37f0 100644
>--- a/rust/hw/char/pl011/src/device.rs
>+++ b/rust/hw/char/pl011/src/device.rs
>@@ -55,7 +55,7 @@ impl DeviceId {
> }
>
> #[repr(C)]
>-#[derive(Debug, qemu_api_macros::Object)]
>+#[derive(Debug, qemu_api_macros::Object, qemu_api_macros::offsets)]
> /// PL011 Device Model in QEMU
> pub struct PL011State {
> pub parent_obj: SysBusDevice,
>diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml
>index f8d6d03609f..a8f7377106b 100644
>--- a/rust/qemu-api-macros/Cargo.toml
>+++ b/rust/qemu-api-macros/Cargo.toml
>@@ -19,4 +19,4 @@ proc-macro = true
> [dependencies]
> proc-macro2 = "1"
> quote = "1"
>-syn = "2"
>+syn = { version = "2", features = ["extra-traits"] }
>diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
>index a4bc5d01ee8..cf99ac04b8f 100644
>--- a/rust/qemu-api-macros/src/lib.rs
>+++ b/rust/qemu-api-macros/src/lib.rs
>@@ -3,8 +3,34 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
>
> use proc_macro::TokenStream;
>-use quote::quote;
>-use syn::{parse_macro_input, DeriveInput};
>+use proc_macro2::Span;
>+use quote::{quote, quote_spanned};
>+use syn::{
>+ parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Data, DeriveInput, Field,
>+ Fields, Ident, Type, Visibility,
>+};
>+
>+struct CompileError(String, Span);
>+
>+impl From<CompileError> for proc_macro2::TokenStream {
>+ fn from(err: CompileError) -> Self {
>+ let CompileError(msg, span) = err;
>+ quote_spanned! { span => compile_error!(#msg); }
>+ }
>+}
>+
>+fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), CompileError> {
>+ let expected = parse_quote! { #[repr(C)] };
>+
>+ if input.attrs.iter().any(|attr| attr == &expected) {
>+ Ok(())
>+ } else {
>+ Err(CompileError(
>+ format!("#[repr(C)] required for {}", msg),
>+ input.ident.span(),
>+ ))
>+ }
>+}
>
> #[proc_macro_derive(Object)]
> pub fn derive_object(input: TokenStream) -> TokenStream {
>@@ -21,3 +47,48 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
>
> TokenStream::from(expanded)
> }
>+
>+fn get_fields(input: &DeriveInput) -> Result<&Punctuated<Field, Comma>, CompileError> {
>+ if let Data::Struct(s) = &input.data {
>+ if let Fields::Named(fs) = &s.fields {
>+ Ok(&fs.named)
>+ } else {
>+ Err(CompileError(
>+ "Cannot generate offsets for unnamed fields.".to_string(),
>+ input.ident.span(),
>+ ))
>+ }
>+ } else {
>+ Err(CompileError(
>+ "Cannot generate offsets for union or enum.".to_string(),
>+ input.ident.span(),
>+ ))
>+ }
>+}
>+
>+#[rustfmt::skip::macros(quote)]
>+fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, CompileError> {
>+ is_c_repr(&input, "#[derive(offsets)]")?;
>+
>+ let name = &input.ident;
>+ let fields = get_fields(&input)?;
>+ let field_names: Vec<&Ident> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
>+ let field_types: Vec<&Type> = fields.iter().map(|f| &f.ty).collect();
>+ let field_vis: Vec<&Visibility> = fields.iter().map(|f| &f.vis).collect();
>+
>+ Ok(quote! {
>+ ::qemu_api::with_offsets! {
>+ struct #name {
>+ #(#field_vis #field_names: #field_types,)*
>+ }
>+ }
>+ })
>+}
>+
>+#[proc_macro_derive(offsets)]
>+pub fn derive_offsets(input: TokenStream) -> TokenStream {
>+ let input = parse_macro_input!(input as DeriveInput);
>+ let expanded = derive_offsets_or_error(input).unwrap_or_else(Into::into);
>+
>+ TokenStream::from(expanded)
>+}
>diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
>index e092f61e8f3..cc716d75d46 100644
>--- a/rust/qemu-api/Cargo.toml
>+++ b/rust/qemu-api/Cargo.toml
>@@ -16,9 +16,13 @@ categories = []
> [dependencies]
> qemu_api_macros = { path = "../qemu-api-macros" }
>
>+[build-dependencies]
>+version_check = "~0.9"
>+
> [features]
> default = []
> allocator = []
>
> [lints.rust]
>-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] }
>+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)',
>+ 'cfg(has_offset_of)'] }
>diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs
>index 419b154c2d2..20f8f718b90 100644
>--- a/rust/qemu-api/build.rs
>+++ b/rust/qemu-api/build.rs
>@@ -4,6 +4,8 @@
>
> use std::path::Path;
>
>+use version_check as rustc;
>+
> fn main() {
> if !Path::new("src/bindings.rs").exists() {
> panic!(
>@@ -11,4 +13,11 @@ fn main() {
> (`ninja bindings.rs`) and copy them to src/bindings.rs, or build through meson."
> );
> }
>+
>+ // Check for available rustc features
>+ if rustc::is_min_version("1.77.0").unwrap_or(false) {
>+ println!("cargo:rustc-cfg=has_offset_of");
>+ }
>+
>+ println!("cargo:rerun-if-changed=build.rs");
> }
>diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
>index c950b008d59..6f637af7b1b 100644
>--- a/rust/qemu-api/meson.build
>+++ b/rust/qemu-api/meson.build
>@@ -1,3 +1,9 @@
>+_qemu_api_cfg = ['--cfg', 'MESON']
>+# _qemu_api_cfg += ['--cfg', 'feature="allocator"']
>+if rustc.version().version_compare('>=1.77.0')
>+ _qemu_api_cfg += ['--cfg', 'has_offset_of']
>+endif
>+
> _qemu_api_rs = static_library(
> 'qemu_api',
> structured_sources(
>@@ -6,6 +12,7 @@ _qemu_api_rs = static_library(
> 'src/c_str.rs',
> 'src/definitions.rs',
> 'src/device_class.rs',
>+ 'src/offset_of.rs',
> 'src/vmstate.rs',
> 'src/zeroable.rs',
> ],
>@@ -13,10 +20,7 @@ _qemu_api_rs = static_library(
> ),
> override_options: ['rust_std=2021', 'build.rust_std=2021'],
> rust_abi: 'rust',
>- rust_args: [
>- '--cfg', 'MESON',
>- # '--cfg', 'feature="allocator"',
>- ],
>+ rust_args: _qemu_api_cfg,
> )
>
> rust.test('rust-qemu-api-tests', _qemu_api_rs,
>diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
>index cb4573ca6ef..56608c7f7fc 100644
>--- a/rust/qemu-api/src/device_class.rs
>+++ b/rust/qemu-api/src/device_class.rs
>@@ -23,23 +23,23 @@ macro_rules! device_class_init {
>
> #[macro_export]
> macro_rules! define_property {
>- ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
>+ ($name:expr, $state:ty, $field:ident, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
> $crate::bindings::Property {
> // use associated function syntax for type checking
> name: ::std::ffi::CStr::as_ptr($name),
> info: $prop,
>- offset: ::core::mem::offset_of!($state, $field) as isize,
>+ offset: $crate::offset_of!($state, $field) as isize,
> set_default: true,
> defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
> ..$crate::zeroable::Zeroable::ZERO
> }
> };
>- ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
>+ ($name:expr, $state:ty, $field:ident, $prop:expr, $type:expr$(,)*) => {
> $crate::bindings::Property {
> // use associated function syntax for type checking
> name: ::std::ffi::CStr::as_ptr($name),
> info: $prop,
>- offset: ::core::mem::offset_of!($state, $field) as isize,
>+ offset: $crate::offset_of!($state, $field) as isize,
> set_default: false,
> ..$crate::zeroable::Zeroable::ZERO
> }
>diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
>index e6bd953e10b..aa8d16ec94b 100644
>--- a/rust/qemu-api/src/lib.rs
>+++ b/rust/qemu-api/src/lib.rs
>@@ -32,6 +32,7 @@ unsafe impl Sync for bindings::VMStateInfo {}
> pub mod c_str;
> pub mod definitions;
> pub mod device_class;
>+pub mod offset_of;
> pub mod vmstate;
> pub mod zeroable;
>
>@@ -169,3 +170,6 @@ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
> }
> }
> }
>+
>+#[cfg(has_offset_of)]
>+pub use core::mem::offset_of;
>diff --git a/rust/qemu-api/src/offset_of.rs b/rust/qemu-api/src/offset_of.rs
>new file mode 100644
>index 00000000000..075e98f986b
>--- /dev/null
>+++ b/rust/qemu-api/src/offset_of.rs
>@@ -0,0 +1,161 @@
>+// SPDX-License-Identifier: MIT
>+
>+/// This macro provides the same functionality as `core::mem::offset_of`,
>+/// except that only one level of field access is supported. The declaration
>+/// of the struct must be wrapped with `with_offsets! { }`.
>+///
>+/// It is needed because `offset_of!` was only stabilized in Rust 1.77.
>+#[cfg(not(has_offset_of))]
>+#[macro_export]
>+macro_rules! offset_of {
>+ ($Container:ty, $field:ident) => {
>+ <$Container>::OFFSET_TO__.$field
>+ };
>+}
>+
>+/// A wrapper for struct declarations, that allows using `offset_of!` in
>+/// versions of Rust prior to 1.77
>+#[macro_export]
>+macro_rules! with_offsets {
>+ // This method to generate field offset constants comes from:
>+ //
>+ // https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df
>+ //
>+ // used under MIT license with permission of Yandros aka Daniel Henry-Mantilla
>+ (
>+ $(#[$struct_meta:meta])*
>+ $struct_vis:vis
>+ struct $StructName:ident {
>+ $(
>+ $(#[$field_meta:meta])*
>+ $field_vis:vis
>+ $field_name:ident : $field_ty:ty
>+ ),*
>+ $(,)?
>+ }
>+ ) => (
>+ #[cfg(not(has_offset_of))]
>+ const _: () = {
>+ struct StructOffsetsHelper<T>(std::marker::PhantomData<T>);
>+ const END_OF_PREV_FIELD: usize = 0;
>+
>+ // populate StructOffsetsHelper<T> with associated consts,
>+ // one for each field
>+ $crate::with_offsets! {
>+ @struct $StructName
>+ @names [ $($field_name)* ]
>+ @tys [ $($field_ty ,)*]
>+ }
>+
>+ // now turn StructOffsetsHelper<T>'s consts into a single struct,
>+ // applying field visibility. This provides better error messages
>+ // than if offset_of! used StructOffsetsHelper::<T> directly.
>+ pub
>+ struct StructOffsets {
>+ $(
>+ $field_vis
>+ $field_name: usize,
>+ )*
>+ }
>+ impl $StructName {
>+ pub
>+ const OFFSET_TO__: StructOffsets = StructOffsets {
>+ $(
>+ $field_name: StructOffsetsHelper::<$StructName>::$field_name,
>+ )*
>+ };
>+ }
>+ };
>+ );
>+
>+ (
>+ @struct $StructName:ident
>+ @names []
>+ @tys []
>+ ) => ();
>+
>+ (
>+ @struct $StructName:ident
>+ @names [$field_name:ident $($other_names:tt)*]
>+ @tys [$field_ty:ty , $($other_tys:tt)*]
>+ ) => (
>+ #[allow(non_local_definitions)]
>+ #[allow(clippy::modulo_one)]
>+ impl StructOffsetsHelper<$StructName> {
>+ #[allow(nonstandard_style)]
>+ const $field_name: usize = {
>+ const ALIGN: usize = std::mem::align_of::<$field_ty>();
>+ const TRAIL: usize = END_OF_PREV_FIELD % ALIGN;
>+ END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL })
>+ };
>+ }
>+ const _: () = {
>+ const END_OF_PREV_FIELD: usize =
>+ StructOffsetsHelper::<$StructName>::$field_name +
>+ std::mem::size_of::<$field_ty>()
>+ ;
>+ $crate::with_offsets! {
>+ @struct $StructName
>+ @names [$($other_names)*]
>+ @tys [$($other_tys)*]
>+ }
>+ };
>+ );
>+}
>+
>+#[cfg(test)]
>+mod tests {
>+ use crate::offset_of;
>+
>+ #[repr(C)]
>+ struct Foo {
>+ a: u16,
>+ b: u32,
>+ c: u64,
>+ d: u16,
>+ }
>+
>+ #[repr(C)]
>+ struct Bar {
>+ pub a: u16,
>+ pub b: u64,
>+ c: Foo,
>+ d: u64,
>+ }
>+
>+ crate::with_offsets! {
>+ #[repr(C)]
>+ struct Bar {
>+ pub a: u16,
>+ pub b: u64,
>+ c: Foo,
>+ d: u64,
>+ }
>+ }
>+
>+ #[repr(C)]
>+ pub struct Baz {
>+ b: u32,
>+ a: u8,
>+ }
>+ crate::with_offsets! {
>+ #[repr(C)]
>+ pub struct Baz {
>+ b: u32,
>+ a: u8,
>+ }
>+ }
>+
>+ #[test]
>+ fn test_offset_of() {
>+ const OFFSET_TO_C: usize = offset_of!(Bar, c);
>+
>+ assert_eq!(offset_of!(Bar, a), 0);
>+ assert_eq!(offset_of!(Bar, b), 8);
>+ assert_eq!(OFFSET_TO_C, 16);
>+ assert_eq!(offset_of!(Bar, d), 40);
>+
>+ assert_eq!(offset_of!(Baz, b), 0);
>+ assert_eq!(offset_of!(Baz, a), 4);
>+ }
>+}
>diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
>index 9c252ce18ef..bedcf1e8f39 100644
>--- a/rust/qemu-api/src/vmstate.rs
>+++ b/rust/qemu-api/src/vmstate.rs
>@@ -58,7 +58,7 @@ macro_rules! vmstate_single_test {
> .as_bytes()
> .as_ptr() as *const ::std::os::raw::c_char,
> err_hint: ::core::ptr::null(),
>- offset: ::core::mem::offset_of!($struct_name, $field_name),
>+ offset: $crate::offset_of!($struct_name, $field_name),
> size: $size,
> start: 0,
> num: 0,
>@@ -135,7 +135,7 @@ macro_rules! vmstate_array {
> .as_bytes()
> .as_ptr() as *const ::std::os::raw::c_char,
> err_hint: ::core::ptr::null(),
>- offset: ::core::mem::offset_of!($struct_name, $field_name),
>+ offset: $crate::offset_of!($struct_name, $field_name),
> size: $size,
> start: 0,
> num: $length as _,
>@@ -183,7 +183,7 @@ macro_rules! vmstate_struct_pointer_v {
> .as_bytes()
> .as_ptr() as *const ::std::os::raw::c_char,
> err_hint: ::core::ptr::null(),
>- offset: ::core::mem::offset_of!($struct_name, $field_name),
>+ offset: $crate::offset_of!($struct_name, $field_name),
> size: ::core::mem::size_of::<*const $type>(),
> start: 0,
> num: 0,
>@@ -212,7 +212,7 @@ macro_rules! vmstate_array_of_pointer {
> info: unsafe { $info },
> size: ::core::mem::size_of::<*const $type>(),
> flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
>- offset: ::core::mem::offset_of!($struct_name, $field_name),
>+ offset: $crate::offset_of!($struct_name, $field_name),
> err_hint: ::core::ptr::null(),
> start: 0,
> num_offset: 0,
>@@ -241,7 +241,7 @@ macro_rules! vmstate_array_of_pointer_to_struct {
> | VMStateFlags::VMS_STRUCT.0
> | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
> ),
>- offset: ::core::mem::offset_of!($struct_name, $field_name),
>+ offset: $crate::offset_of!($struct_name, $field_name),
> err_hint: ::core::ptr::null(),
> start: 0,
> num_offset: 0,
>diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
>index 381ac84657b..7442f695646 100644
>--- a/rust/qemu-api/tests/tests.rs
>+++ b/rust/qemu-api/tests/tests.rs
>@@ -21,6 +21,7 @@ fn test_device_decl_macros() {
> ..Zeroable::ZERO
> };
>
>+ #[derive(qemu_api_macros::offsets)]
> #[repr(C)]
> #[derive(qemu_api_macros::Object)]
> pub struct DummyState {
>diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build
>index a53335f3092..9f56ce1c24d 100644
>--- a/subprojects/packagefiles/syn-2-rs/meson.build
>+++ b/subprojects/packagefiles/syn-2-rs/meson.build
>@@ -24,6 +24,7 @@ _syn_rs = static_library(
> '--cfg', 'feature="printing"',
> '--cfg', 'feature="clone-impls"',
> '--cfg', 'feature="proc-macro"',
>+ '--cfg', 'feature="extra-traits"',
> ],
> dependencies: [
> quote_dep,
>--
>2.47.0
>
Compilation fails for me, on macos / rustc 1.80.1
error[E0369]: binary operation `==` cannot be applied to type
`&Attribute`
--> ../rust/qemu-api-macros/src/lib.rs:25:43
|
25 | if input.attrs.iter().any(|attr| attr == &expected) {
| ---- ^^ --------- &_
| |
| &Attribute
error: aborting due to 1 previous error
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 32/40] rust: introduce alternative implementation of offset_of!
2024-11-07 11:28 ` Manos Pitsidianakis
@ 2024-11-07 11:31 ` Paolo Bonzini
2024-11-07 12:44 ` Manos Pitsidianakis
0 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-11-07 11:31 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: qemu-devel, Alex Benné e, Junjie Mao, Kevin Wolf,
Pierrick Bouvier, Zhao Liu
> Compilation fails for me, on macos / rustc 1.80.1
>
> error[E0369]: binary operation `==` cannot be applied to type
> `&Attribute`
> --> ../rust/qemu-api-macros/src/lib.rs:25:43
> |
> 25 | if input.attrs.iter().any(|attr| attr == &expected) {
> | ---- ^^ --------- &_
> | |
> | &Attribute
>
> error: aborting due to 1 previous error
You need "meson subprojects update --reset" as mentioned in
the cover letter.
Paolo
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 32/40] rust: introduce alternative implementation of offset_of!
2024-11-07 11:31 ` Paolo Bonzini
@ 2024-11-07 12:44 ` Manos Pitsidianakis
0 siblings, 0 replies; 52+ messages in thread
From: Manos Pitsidianakis @ 2024-11-07 12:44 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Alex Benné e, Junjie Mao, Kevin Wolf,
Pierrick Bouvier, Zhao Liu
On Thu, 07 Nov 2024 11:31, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Compilation fails for me, on macos / rustc 1.80.1
>>
>> error[E0369]: binary operation `==` cannot be applied to type
>> `&Attribute`
>> --> ../rust/qemu-api-macros/src/lib.rs:25:43
>> |
>> 25 | if input.attrs.iter().any(|attr| attr == &expected) {
>> | ---- ^^ --------- &_
>> | |
>> | &Attribute
>>
>> error: aborting due to 1 previous error
>
>You need "meson subprojects update --reset" as mentioned in
>the cover letter.
>
>Paolo
>
I did already, also purged the build dir. I had to delete the cached syn
subproject (`rm -rf subprojects/syn-2.0.66`) to make it work FYI
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 12/40] rust: build integration test for the qemu_api crate
2024-11-04 17:26 ` [PULL 12/40] rust: build integration test for the qemu_api crate Paolo Bonzini
@ 2024-12-19 9:53 ` Bernhard Beschow
2024-12-19 11:22 ` Paolo Bonzini
0 siblings, 1 reply; 52+ messages in thread
From: Bernhard Beschow @ 2024-12-19 9:53 UTC (permalink / raw)
To: qemu-devel, Paolo Bonzini
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Am 4. November 2024 17:26:51 UTC schrieb Paolo Bonzini <pbonzini@redhat.com>:
>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>
>---
> meson.build | 10 ++++-
> rust/qemu-api/meson.build | 26 ++++++++++--
> rust/qemu-api/src/lib.rs | 3 --
> rust/qemu-api/src/tests.rs | 49 ----------------------
> rust/qemu-api/tests/tests.rs | 78 ++++++++++++++++++++++++++++++++++++
> 5 files changed, 110 insertions(+), 56 deletions(-)
> delete mode 100644 rust/qemu-api/src/tests.rs
> create mode 100644 rust/qemu-api/tests/tests.rs
When `--enable-modules` is passed to configure, this patch results in numerous undefined symbols.
Best regards,
Bernhard
>
>diff --git a/meson.build b/meson.build
>index 34328f7394c..d360120b233 100644
>--- a/meson.build
>+++ b/meson.build
>@@ -3340,7 +3340,15 @@ if have_rust and have_system
>
> # Prohibit code that is forbidden in Rust 2024
> rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
>- add_project_arguments(rustc_args, native: false, language: 'rust')
>+
>+ # Apart from procedural macros, our Rust executables will often link
>+ # with C code, so include all the libraries that C code needs. This
>+ # is safe; https://github.com/rust-lang/rust/pull/54675 says that
>+ # passing -nodefaultlibs to the linker "was more ideological to
>+ # start with than anything".
>+ add_project_arguments(rustc_args + ['-C', 'default-linker-libraries'],
>+ native: false, language: 'rust')
>+
> add_project_arguments(rustc_args, native: true, language: 'rust')
> endif
>
>diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
>index 42ea815fa5a..1fc36078027 100644
>--- a/rust/qemu-api/meson.build
>+++ b/rust/qemu-api/meson.build
>@@ -14,11 +14,31 @@ _qemu_api_rs = static_library(
> '--cfg', 'MESON',
> # '--cfg', 'feature="allocator"',
> ],
>- dependencies: [
>- qemu_api_macros,
>- ],
> )
>
> qemu_api = declare_dependency(
> link_with: _qemu_api_rs,
>+ dependencies: qemu_api_macros,
> )
>+
>+# Rust executables do not support objects, so add an intermediate step.
>+rust_qemu_api_objs = static_library(
>+ 'rust_qemu_api_objs',
>+ objects: [libqom.extract_all_objects(recursive: false),
>+ libhwcore.extract_all_objects(recursive: false)])
>+
>+test('rust-qemu-api-integration',
>+ executable(
>+ 'rust-qemu-api-integration',
>+ 'tests/tests.rs',
>+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
>+ rust_args: ['--test'],
>+ install: false,
>+ dependencies: [qemu_api, qemu_api_macros],
>+ link_whole: [rust_qemu_api_objs, libqemuutil]),
>+ args: [
>+ '--test',
>+ '--format', 'pretty',
>+ ],
>+ protocol: 'rust',
>+ suite: ['unit', 'rust'])
>diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
>index e72fb4b4bb1..6bc68076aae 100644
>--- a/rust/qemu-api/src/lib.rs
>+++ b/rust/qemu-api/src/lib.rs
>@@ -30,9 +30,6 @@ unsafe impl Sync for bindings::VMStateDescription {}
> pub mod definitions;
> pub mod device_class;
>
>-#[cfg(test)]
>-mod tests;
>-
> use std::alloc::{GlobalAlloc, Layout};
>
> #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
>diff --git a/rust/qemu-api/src/tests.rs b/rust/qemu-api/src/tests.rs
>deleted file mode 100644
>index df54edbd4e2..00000000000
>--- a/rust/qemu-api/src/tests.rs
>+++ /dev/null
>@@ -1,49 +0,0 @@
>-// Copyright 2024, Linaro Limited
>-// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>-// SPDX-License-Identifier: GPL-2.0-or-later
>-
>-use crate::{
>- bindings::*, declare_properties, define_property, device_class_init, vm_state_description,
>-};
>-
>-#[test]
>-fn test_device_decl_macros() {
>- // Test that macros can compile.
>- vm_state_description! {
>- VMSTATE,
>- name: c"name",
>- unmigratable: true,
>- }
>-
>- #[repr(C)]
>- pub struct DummyState {
>- pub char_backend: CharBackend,
>- pub migrate_clock: bool,
>- }
>-
>- declare_properties! {
>- DUMMY_PROPERTIES,
>- define_property!(
>- c"chardev",
>- DummyState,
>- char_backend,
>- unsafe { &qdev_prop_chr },
>- CharBackend
>- ),
>- define_property!(
>- c"migrate-clk",
>- DummyState,
>- migrate_clock,
>- unsafe { &qdev_prop_bool },
>- bool
>- ),
>- }
>-
>- device_class_init! {
>- dummy_class_init,
>- props => DUMMY_PROPERTIES,
>- realize_fn => None,
>- reset_fn => None,
>- vmsd => VMSTATE,
>- }
>-}
>diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
>new file mode 100644
>index 00000000000..aa1e0568c69
>--- /dev/null
>+++ b/rust/qemu-api/tests/tests.rs
>@@ -0,0 +1,78 @@
>+// Copyright 2024, Linaro Limited
>+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>+// SPDX-License-Identifier: GPL-2.0-or-later
>+
>+use core::ffi::CStr;
>+
>+use qemu_api::{
>+ bindings::*,
>+ declare_properties, define_property,
>+ definitions::{Class, ObjectImpl},
>+ device_class_init, vm_state_description,
>+};
>+
>+#[test]
>+fn test_device_decl_macros() {
>+ // Test that macros can compile.
>+ vm_state_description! {
>+ VMSTATE,
>+ name: c"name",
>+ unmigratable: true,
>+ }
>+
>+ #[repr(C)]
>+ #[derive(qemu_api_macros::Object)]
>+ pub struct DummyState {
>+ pub _parent: DeviceState,
>+ pub migrate_clock: bool,
>+ }
>+
>+ #[repr(C)]
>+ pub struct DummyClass {
>+ pub _parent: DeviceClass,
>+ }
>+
>+ declare_properties! {
>+ DUMMY_PROPERTIES,
>+ define_property!(
>+ c"migrate-clk",
>+ DummyState,
>+ migrate_clock,
>+ unsafe { &qdev_prop_bool },
>+ bool
>+ ),
>+ }
>+
>+ device_class_init! {
>+ dummy_class_init,
>+ props => DUMMY_PROPERTIES,
>+ realize_fn => None,
>+ legacy_reset_fn => None,
>+ vmsd => VMSTATE,
>+ }
>+
>+ impl ObjectImpl for DummyState {
>+ type Class = DummyClass;
>+ const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
>+ const TYPE_NAME: &'static CStr = c"dummy";
>+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_DEVICE);
>+ const ABSTRACT: bool = false;
>+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
>+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
>+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
>+ }
>+
>+ impl Class for DummyClass {
>+ const CLASS_INIT: Option<
>+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
>+ > = Some(dummy_class_init);
>+ const CLASS_BASE_INIT: Option<
>+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
>+ > = None;
>+ }
>+
>+ unsafe {
>+ module_call_init(module_init_type::MODULE_INIT_QOM);
>+ object_unref(object_new(DummyState::TYPE_NAME.as_ptr()) as *mut _);
>+ }
>+}
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 12/40] rust: build integration test for the qemu_api crate
2024-12-19 9:53 ` Bernhard Beschow
@ 2024-12-19 11:22 ` Paolo Bonzini
2024-12-20 10:42 ` Paolo Bonzini
0 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-12-19 11:22 UTC (permalink / raw)
To: Bernhard Beschow, qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
On 12/19/24 10:53, Bernhard Beschow wrote:
>
>
> Am 4. November 2024 17:26:51 UTC schrieb Paolo Bonzini <pbonzini@redhat.com>:
>> 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>
>> ---
>> meson.build | 10 ++++-
>> rust/qemu-api/meson.build | 26 ++++++++++--
>> rust/qemu-api/src/lib.rs | 3 --
>> rust/qemu-api/src/tests.rs | 49 ----------------------
>> rust/qemu-api/tests/tests.rs | 78 ++++++++++++++++++++++++++++++++++++
>> 5 files changed, 110 insertions(+), 56 deletions(-)
>> delete mode 100644 rust/qemu-api/src/tests.rs
>> create mode 100644 rust/qemu-api/tests/tests.rs
>
> When `--enable-modules` is passed to configure, this patch results in numerous undefined symbols.
Thanks for the report... This doesn't seem easy to fix without adding
more hacks on top, but I'll try to do it right.
Paolo
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PULL 12/40] rust: build integration test for the qemu_api crate
2024-12-19 11:22 ` Paolo Bonzini
@ 2024-12-20 10:42 ` Paolo Bonzini
2024-12-21 18:49 ` Bernhard Beschow
0 siblings, 1 reply; 52+ messages in thread
From: Paolo Bonzini @ 2024-12-20 10:42 UTC (permalink / raw)
To: Bernhard Beschow, qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
On Thu, Dec 19, 2024 at 12:22 PM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 12/19/24 10:53, Bernhard Beschow wrote:
> >
> >
> > Am 4. November 2024 17:26:51 UTC schrieb Paolo Bonzini <pbonzini@redhat.com>:
> >> 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>
> >> ---
> >> meson.build | 10 ++++-
> >> rust/qemu-api/meson.build | 26 ++++++++++--
> >> rust/qemu-api/src/lib.rs | 3 --
> >> rust/qemu-api/src/tests.rs | 49 ----------------------
> >> rust/qemu-api/tests/tests.rs | 78 ++++++++++++++++++++++++++++++++++++
> >> 5 files changed, 110 insertions(+), 56 deletions(-)
> >> delete mode 100644 rust/qemu-api/src/tests.rs
> >> create mode 100644 rust/qemu-api/tests/tests.rs
> >
> > When `--enable-modules` is passed to configure, this patch results in numerous undefined symbols.
>
> Thanks for the report... This doesn't seem easy to fix without adding
> more hacks on top, but I'll try to do it right.
Which might very well be doing it in Meson. One needs to teach Meson
to add --start-group/--end-group options for rustc just like Meson does
for the C compiler; or alternatively to support "objects: ..." for
Rust executables.
For example, with https://github.com/mesonbuild/meson/pull/14026, the fix
is simply this:
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 9425ba7100c..0c08d2e51f5 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -59,7 +59,8 @@ test('rust-qemu-api-integration',
rust_args: ['--test'],
install: false,
dependencies: [qemu_api, qemu_api_macros],
- link_whole: [rust_qemu_api_objs, libqemuutil]),
+ link_with: libqemuutil,
+ link_whole: [rust_qemu_api_objs]),
args: [
'--test', '--test-threads', '1',
'--format', 'pretty',
Until then, --enable-modules is broken together with Rust.
Paolo
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PULL 12/40] rust: build integration test for the qemu_api crate
2024-12-20 10:42 ` Paolo Bonzini
@ 2024-12-21 18:49 ` Bernhard Beschow
0 siblings, 0 replies; 52+ messages in thread
From: Bernhard Beschow @ 2024-12-21 18:49 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel
Cc: Alex Bennée, Junjie Mao, Kevin Wolf, Manos Pitsidianakis,
Pierrick Bouvier, Zhao Liu
Am 20. Dezember 2024 10:42:09 UTC schrieb Paolo Bonzini <pbonzini@redhat.com>:
>
>
>On Thu, Dec 19, 2024 at 12:22 PM Paolo Bonzini <pbonzini@redhat.com> wrote:
>>
>> On 12/19/24 10:53, Bernhard Beschow wrote:
>> >
>> >
>> > Am 4. November 2024 17:26:51 UTC schrieb Paolo Bonzini <pbonzini@redhat.com>:
>> >> 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>
>> >> ---
>> >> meson.build | 10 ++++-
>> >> rust/qemu-api/meson.build | 26 ++++++++++--
>> >> rust/qemu-api/src/lib.rs | 3 --
>> >> rust/qemu-api/src/tests.rs | 49 ----------------------
>> >> rust/qemu-api/tests/tests.rs | 78 ++++++++++++++++++++++++++++++++++++
>> >> 5 files changed, 110 insertions(+), 56 deletions(-)
>> >> delete mode 100644 rust/qemu-api/src/tests.rs
>> >> create mode 100644 rust/qemu-api/tests/tests.rs
>> >
>> > When `--enable-modules` is passed to configure, this patch results in numerous undefined symbols.
>>
>> Thanks for the report... This doesn't seem easy to fix without adding
>> more hacks on top, but I'll try to do it right.
>
>Which might very well be doing it in Meson. One needs to teach Meson
>to add --start-group/--end-group options for rustc just like Meson does
>for the C compiler; or alternatively to support "objects: ..." for
>Rust executables.
>
>For example, with https://github.com/mesonbuild/meson/pull/14026, the fix
>is simply this:
>
>diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
>index 9425ba7100c..0c08d2e51f5 100644
>--- a/rust/qemu-api/meson.build
>+++ b/rust/qemu-api/meson.build
>@@ -59,7 +59,8 @@ test('rust-qemu-api-integration',
> rust_args: ['--test'],
> install: false,
> dependencies: [qemu_api, qemu_api_macros],
>- link_whole: [rust_qemu_api_objs, libqemuutil]),
>+ link_with: libqemuutil,
>+ link_whole: [rust_qemu_api_objs]),
> args: [
> '--test', '--test-threads', '1',
> '--format', 'pretty',
>
>Until then, --enable-modules is broken together with Rust.
Thanks for figuring this out! Your latest patches really motivated me to try out the Rust support. I especially liked the patch leveraging GATs for storing metadata inside the type system which seems like idiomatic Rust to me. Great work!
Best regards,
Bernhard
>
>Paolo
>
^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2024-12-21 19:13 UTC | newest]
Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-04 17:26 [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Paolo Bonzini
2024-11-04 17:26 ` [PULL 01/40] qdev: make properties array "const" Paolo Bonzini
2024-11-04 17:26 ` [PULL 02/40] rust/wrapper.h: define memory_order enum Paolo Bonzini
2024-11-04 17:26 ` [PULL 03/40] Revert "rust: add PL011 device model" Paolo Bonzini
2024-11-04 17:26 ` [PULL 04/40] rust: add PL011 device model Paolo Bonzini
2024-11-04 17:26 ` [PULL 05/40] meson: import rust module into a global variable Paolo Bonzini
2024-11-04 17:26 ` [PULL 06/40] meson: remove repeated search for rust_root_crate.sh Paolo Bonzini
2024-11-04 17:26 ` [PULL 07/40] meson: pass rustc_args when building all crates Paolo Bonzini
2024-11-04 17:26 ` [PULL 08/40] rust: do not always select X_PL011_RUST Paolo Bonzini
2024-11-04 17:26 ` [PULL 09/40] rust: do not use --no-size_t-is-usize Paolo Bonzini
2024-11-04 17:26 ` [PULL 10/40] rust: remove uses of #[no_mangle] Paolo Bonzini
2024-11-04 17:26 ` [PULL 11/40] rust: modernize link_section usage for ELF platforms Paolo Bonzini
2024-11-04 17:26 ` [PULL 12/40] rust: build integration test for the qemu_api crate Paolo Bonzini
2024-12-19 9:53 ` Bernhard Beschow
2024-12-19 11:22 ` Paolo Bonzini
2024-12-20 10:42 ` Paolo Bonzini
2024-12-21 18:49 ` Bernhard Beschow
2024-11-04 17:26 ` [PULL 13/40] rust: cleanup module_init!, use it from #[derive(Object)] Paolo Bonzini
2024-11-04 17:26 ` [PULL 14/40] rust: clean up define_property macro Paolo Bonzini
2024-11-04 17:26 ` [PULL 15/40] rust: make properties array immutable Paolo Bonzini
2024-11-04 17:26 ` [PULL 16/40] rust: provide safe wrapper for MaybeUninit::zeroed() Paolo Bonzini
2024-11-04 17:26 ` [PULL 17/40] rust: do not use TYPE_CHARDEV unnecessarily Paolo Bonzini
2024-11-04 17:26 ` [PULL 18/40] rust: add definitions for vmstate Paolo Bonzini
2024-11-04 17:26 ` [PULL 19/40] rust/pl011: fix default value for migrate-clock Paolo Bonzini
2024-11-04 17:26 ` [PULL 20/40] rust/pl011: add support for migration Paolo Bonzini
2024-11-04 17:27 ` [PULL 21/40] rust/pl011: move CLK_NAME static to function scope Paolo Bonzini
2024-11-04 17:27 ` [PULL 22/40] rust/pl011: add TYPE_PL011_LUMINARY device Paolo Bonzini
2024-11-04 17:27 ` [PULL 23/40] rust/pl011: remove commented out C code Paolo Bonzini
2024-11-04 17:27 ` [PULL 24/40] rust/pl011: Use correct masks for IBRD and FBRD Paolo Bonzini
2024-11-04 17:27 ` [PULL 25/40] rust: patch bilge-impl to allow compilation with 1.63.0 Paolo Bonzini
2024-11-04 17:27 ` [PULL 26/40] rust: fix cfgs of proc-macro2 for 1.63.0 Paolo Bonzini
2024-11-04 17:27 ` [PULL 27/40] rust: use std::os::raw instead of core::ffi Paolo Bonzini
2024-11-04 17:27 ` [PULL 28/40] rust: introduce a c_str macro Paolo Bonzini
2024-11-04 17:27 ` [PULL 29/40] rust: silence unknown warnings for the sake of old compilers Paolo Bonzini
2024-11-04 17:27 ` [PULL 30/40] rust: synchronize dependencies between subprojects and Cargo.lock Paolo Bonzini
2024-11-04 17:27 ` [PULL 31/40] rust: create a cargo workspace Paolo Bonzini
2024-11-04 17:27 ` [PULL 32/40] rust: introduce alternative implementation of offset_of! Paolo Bonzini
2024-11-07 11:28 ` Manos Pitsidianakis
2024-11-07 11:31 ` Paolo Bonzini
2024-11-07 12:44 ` Manos Pitsidianakis
2024-11-04 17:27 ` [PULL 33/40] rust: do not use MaybeUninit::zeroed() Paolo Bonzini
2024-11-04 17:27 ` [PULL 34/40] rust: clean up detection of the language Paolo Bonzini
2024-11-04 17:27 ` [PULL 35/40] rust: allow version 1.63.0 of rustc Paolo Bonzini
2024-11-04 17:27 ` [PULL 36/40] rust: do not use --generate-cstr Paolo Bonzini
2024-11-04 17:27 ` [PULL 37/40] rust: allow older version of bindgen Paolo Bonzini
2024-11-04 17:27 ` [PULL 38/40] rust: make rustfmt optional Paolo Bonzini
2024-11-04 17:27 ` [PULL 39/40] dockerfiles: install bindgen from cargo on Ubuntu 22.04 Paolo Bonzini
2024-11-04 17:27 ` [PULL 40/40] ci: enable rust in the Debian and Ubuntu system build job Paolo Bonzini
2024-11-06 13:10 ` [PULL 00/40] Rust changes for QEMU 9.2 soft freeze Peter Maydell
2024-11-06 13:14 ` Paolo Bonzini
2024-11-06 14:59 ` Peter Maydell
2024-11-06 16:27 ` Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).