Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-07-10 Thread Manos Pitsidianakis
Hey Zhao,

On Thu, 11 Jul 2024 at 07:05, Zhao Liu  wrote:
>
> Hi Manos and all,
>
> On Tue, Jun 11, 2024 at 01:33:32PM +0300, Manos Pitsidianakis wrote:
> > diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> > new file mode 100644
> > index 00..ebecb99fe0
> > --- /dev/null
> > +++ b/rust/rustfmt.toml
> > @@ -0,0 +1,7 @@
> > +edition = "2021"
> > +format_generated_files = false
> > +format_code_in_doc_comments = true
> > +format_strings = true
> > +imports_granularity = "Crate"
> > +group_imports = "StdExternalCrate"
> > +wrap_comments = true
> >
>
> I find it's stiil necessary to strictly limit the width of the lines by
> "error_on_line_overflow = true" [1].
>
> Currently rustfmt defaults the width limitation with "max_width = 100",
> but it has bugs and doesn't always work. For example, the line of
> rust/qemu-api/src/device_class.rs:108 comes to 157 characters and is
> ignored by rustfmt, which doesn't even fit in one line of my screen!
>
> Of course I think it's feasible to manually review and fix similar cases,
> but it's definitely better to have readily available tool that can help
> us rigorously formatted...
>
> [1]: 
> https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#error_on_line_overflow
>
> -Zhao

Thank you for pointing that out, I hadn't noticed it! The problem is
that macro definitions are also macros and macros aren't formatted
because they have to be expanded, IIUC. I agree that a hard error on
an overflow is necessary for readable code.

By the way, my usual go-to workaround for this bug is to format the
macro body outside the macro_rules! { } scope, (rustfmt works even if
the code does not compile) and then put it back in.

Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-07-10 Thread Zhao Liu
Hi Manos and all,

On Tue, Jun 11, 2024 at 01:33:32PM +0300, Manos Pitsidianakis wrote:
> diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> new file mode 100644
> index 00..ebecb99fe0
> --- /dev/null
> +++ b/rust/rustfmt.toml
> @@ -0,0 +1,7 @@
> +edition = "2021"
> +format_generated_files = false
> +format_code_in_doc_comments = true
> +format_strings = true
> +imports_granularity = "Crate"
> +group_imports = "StdExternalCrate"
> +wrap_comments = true
>

I find it's stiil necessary to strictly limit the width of the lines by
"error_on_line_overflow = true" [1].

Currently rustfmt defaults the width limitation with "max_width = 100",
but it has bugs and doesn't always work. For example, the line of
rust/qemu-api/src/device_class.rs:108 comes to 157 characters and is
ignored by rustfmt, which doesn't even fit in one line of my screen!

Of course I think it's feasible to manually review and fix similar cases,
but it's definitely better to have readily available tool that can help
us rigorously formatted...

[1]: 
https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#error_on_line_overflow

-Zhao




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-19 Thread Paolo Bonzini
Il mer 19 giu 2024, 18:54 Daniel P. Berrangé  ha
scritto:

> >build/
> >  rust/
> >.cargo/
> >  config.toml   # generated by configure or meson.build
> >Cargo.toml  # workspace generated by configure or meson.build
> >Cargo.lock  # can be either linked to srctree or generated
> >qemu/   # symlink to srctree/rust/qemu
> >aarch64-softmmu-hw/
> >  Cargo.toml# generated by meson.build (*)
> >  src/  # symlink to srctree/rust/hw/
> >i386-softmmu-hw/
> >  Cargo.toml# generated by meson.build
> >  src/  # symlink to srctree/rust/hw/
> >generated/  # files generated by rust/generated/meson.build
>
> If we're generating a build tree to invoke cargo on, can we then
> avoid creating a completely separate dir hierarchy in the source
> tree rooted at /rust, and just have rust source within our existing
> hierarchy.
>

Maybe... I hadn't even considered the possibility of having a single cargo
invocation (and thus a cargo workspace in the build tree) until Richard
pointed out the duplication in configuration files.

I suppose you could just link rust/aarch64-softmmu-hw to srctree/hw, and
have a srctree/hw/lib.rs file in there to prime the search for submodules.

I think the resulting hierarchy would feel a little foreign though. Without
seeing the code I can't judge but my impression is that, if we wanted to go
that way, I would also move all C code under src/. Perhaps we can consider
such a unification later, once we have more experience, but for now keep
Rust and C code separate?

Paolo



> eg
>
> aarch64-softmmu-hw/
>   Cargo.toml# generated by meson.build (*)
>   src/
> pl011/  # symlink to srctree/hw/p1011/
>
>
> With regards,
> Daniel
> --
> |: https://berrange.com  -o-
> https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o-
> https://fstop138.berrange.com :|
> |: https://entangle-photo.org-o-
> https://www.instagram.com/dberrange :|
>
>


Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-19 Thread Daniel P . Berrangé
On Wed, Jun 19, 2024 at 06:43:01PM +0200, Paolo Bonzini wrote:
> On 6/19/24 07:34, Richard Henderson wrote:
> > First silly question: how much of this is boiler plate that gets moved
> > the moment that the second rust subdirectory is added?
> 
> If my suggestion at 
> https://lore.kernel.org/qemu-devel/CABgObfaP7DRD8dbSKNmUzhZNyxeHWO0MztaW3_EFYt=vf6s...@mail.gmail.com/
> works, we'd have only two directories that have a Cargo.toml in it.  For
> example it could be rust/qemu/ (common code) and rust/hw/ (code that depends
> on Kconfig).
> 
> I think we can also have a rust/Cargo.toml file as in
> https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace,
> and then the various configuration files under rust/ will be valid for all
> subpackages.
> 
> > > +[build]
> > > +rustflags = ["-Crelocation-model=pic", "-Ctarget-feature=+crt-static"]
> > 
> > It seems certain that this is not specific to pl011, and will be commot
> > to other rust subdirectories.  Or, given the .cargo directory name, is
> > this generated by cargo and committed by mistake?
> 
> -Crelocation-mode should be pie.  But also, I am not sure it works because I
> think it's always going to be overridden by cargo_wrapper.py? See
> https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags.
> 
> (I'm not sure what +crt-static is for).
> 
> I think the generate_cfg_flags() mechanism of cargo_wrapper.py has to be
> rewritten from Python to Rust and moved to build.rs (using
> cargo::rustc-cfg).  By doing this, the cfg flags are added to whatever is in
> .cargo/config.toml, rather than replaced.
> 
> > > diff --git a/rust/pl011/.gitignore b/rust/pl011/.gitignore
> > > new file mode 100644
> > > index 00..28a02c847f
> > > --- /dev/null
> > > +++ b/rust/pl011/.gitignore
> > > @@ -0,0 +1,2 @@
> > > +target
> > > +src/generated.rs.inc
> > 
> > Is this a symptom of generating files into the source directory and not
> > build directory?
> 
> If I understand correctly, Manos considered two possible ways to invoke
> cargo on the Rust code:
> 
> - directly, in which case you need to copy the generated source file to
> rust/pl011/src/generated.rs.inc, because cargo does not know where the build
> tree
> 
> - do everything through meson, which does the right thing because
> cargo_wrapper.py knows about the build tree and passes the information.
> 
> To avoid this, the first workflow could be adjusted so that cargo can still
> be invoked directly, _but from the build tree_, not the source tree.  For
> example configure could generate a .../build/.cargo/config.toml with
> 
>[env]
>MESON_BUILD_ROOT = ".../build"
> 
> (extra advantage: -Crelocation-model=pie can be added based on
> --enable-pie/--disable-pie).  configure can also create symlinks in the
> build tree for the source tree's rust/, Cargo.toml and Cargo.lock.
> 
> This allows rust/pl011/src/generated.rs (which probably will become
> something like rust/common/src/generated.rs) to be:
> 
>include!(concat!(env!("MESON_BUILD_ROOT"), "/generated.rs.inc"));
> 
> when cargo is invoked from the build tree.
> 
> Putting everything together you'd have
> 
>build/
>  rust/
>.cargo/
>  config.toml   # generated by configure or meson.build
>Cargo.toml  # workspace generated by configure or meson.build
>Cargo.lock  # can be either linked to srctree or generated
>qemu/   # symlink to srctree/rust/qemu
>aarch64-softmmu-hw/
>  Cargo.toml# generated by meson.build (*)
>  src/  # symlink to srctree/rust/hw/
>i386-softmmu-hw/
>  Cargo.toml# generated by meson.build
>  src/  # symlink to srctree/rust/hw/
>generated/  # files generated by rust/generated/meson.build

If we're generating a build tree to invoke cargo on, can we then
avoid creating a completely separate dir hierarchy in the source
tree rooted at /rust, and just have rust source within our existing
hierarchy.

eg

aarch64-softmmu-hw/
  Cargo.toml# generated by meson.build (*)
  src/
pl011/  # symlink to srctree/hw/p1011/


With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-19 Thread Paolo Bonzini

On 6/19/24 07:34, Richard Henderson wrote:
First silly question: how much of this is boiler plate that gets moved 
the moment that the second rust subdirectory is added?


If my suggestion at 
https://lore.kernel.org/qemu-devel/CABgObfaP7DRD8dbSKNmUzhZNyxeHWO0MztaW3_EFYt=vf6s...@mail.gmail.com/ 
works, we'd have only two directories that have a Cargo.toml in it.  For 
example it could be rust/qemu/ (common code) and rust/hw/ (code that 
depends on Kconfig).


I think we can also have a rust/Cargo.toml file as in 
https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace, 
and then the various configuration files under rust/ will be valid for 
all subpackages.



+[build]
+rustflags = ["-Crelocation-model=pic", "-Ctarget-feature=+crt-static"]


It seems certain that this is not specific to pl011, and will be commot to other rust 
subdirectories.  Or, given the .cargo directory name, is this generated by cargo and 
committed by mistake?


-Crelocation-mode should be pie.  But also, I am not sure it works 
because I think it's always going to be overridden by cargo_wrapper.py? 
See https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags.


(I'm not sure what +crt-static is for).

I think the generate_cfg_flags() mechanism of cargo_wrapper.py has to be 
rewritten from Python to Rust and moved to build.rs (using 
cargo::rustc-cfg).  By doing this, the cfg flags are added to whatever 
is in .cargo/config.toml, rather than replaced.



diff --git a/rust/pl011/.gitignore b/rust/pl011/.gitignore
new file mode 100644
index 00..28a02c847f
--- /dev/null
+++ b/rust/pl011/.gitignore
@@ -0,0 +1,2 @@
+target
+src/generated.rs.inc


Is this a symptom of generating files into the source directory and not 
build directory?


If I understand correctly, Manos considered two possible ways to invoke 
cargo on the Rust code:


- directly, in which case you need to copy the generated source file to 
rust/pl011/src/generated.rs.inc, because cargo does not know where the 
build tree


- do everything through meson, which does the right thing because 
cargo_wrapper.py knows about the build tree and passes the information.


To avoid this, the first workflow could be adjusted so that cargo can 
still be invoked directly, _but from the build tree_, not the source 
tree.  For example configure could generate a 
.../build/.cargo/config.toml with


   [env]
   MESON_BUILD_ROOT = ".../build"

(extra advantage: -Crelocation-model=pie can be added based on 
--enable-pie/--disable-pie).  configure can also create symlinks in the 
build tree for the source tree's rust/, Cargo.toml and Cargo.lock.


This allows rust/pl011/src/generated.rs (which probably will become 
something like rust/common/src/generated.rs) to be:


   include!(concat!(env!("MESON_BUILD_ROOT"), "/generated.rs.inc"));

when cargo is invoked from the build tree.

Putting everything together you'd have

   build/
 rust/
   .cargo/
 config.toml   # generated by configure or meson.build
   Cargo.toml  # workspace generated by configure or meson.build
   Cargo.lock  # can be either linked to srctree or generated
   qemu/   # symlink to srctree/rust/qemu
   aarch64-softmmu-hw/
 Cargo.toml# generated by meson.build (*)
 src/  # symlink to srctree/rust/hw/
   i386-softmmu-hw/
 Cargo.toml# generated by meson.build
 src/  # symlink to srctree/rust/hw/
   generated/  # files generated by rust/generated/meson.build

(*) these have to be generated to change the package name, so 
configure_file() seems like a good match for it.


This is suspiciously similar to what tests/tcg/ looks like, except that 
tests/tcg/*/Makefile is just a symbolic link.  I tried creating a 
similar directory structure in a toy project, and it seemed to work...


Second silly question: does this really need to be committed to the 
repository? It *appears* to be specific to the host+os-version of the 
build.  It is certainly very specific about versions and checksums...


Generally the idea is that libraries should not commit it, while 
applications should commit it.  The idea is that the Cargo.lock file 
reproduces a working configuration, and dependencies are updated to 
known-good releases when CI passes.  I don't think I like this, but it 
is what it is.  I ascribe it to me being from the Jurassic.


But for now I would consider not committing Cargo.lock, because we don't 
have the infrastructure to do that automatic dependency update (assuming 
we want it).  But we could generate it at release time so that it is 
included in tarballs, and create the symlink from 
srctree/rust/Cargo.lock into build/rust/ only if the file is present in 
the source tree.



diff --git a/rust/pl011/Cargo.toml b/rust/pl011/Cargo.toml
[...]
+# bilge deps included here to include them with docs
+[dependencies]
+arbitrary-int = { version = "1.2.7" }
+bilge = { version = "0.2.0" }

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-18 Thread Richard Henderson

On 6/11/24 03:33, Manos Pitsidianakis wrote:

This commit adds a re-implementation of hw/char/pl011.c in Rust.

It uses generated Rust bindings (produced by `ninja
aarch64-softmmu-generated.rs`) to
register itself as a QOM type/class.

How to build:

1. Make sure rust, cargo and bindgen (cargo install bindgen-cli) are
installed


Ah hah.  Nevermind my previous question -- cargo install produces bindgen v0.69.4, quite a 
bit newer than the ubuntu 22.04 packaged version.  I have progressed a bit.


Please bear with me as I attempt to learn Rust in the process of reviewing this.  I 
promise no bikesheding and only to ask silly questions.




  rust/pl011/.cargo/config.toml  |   2 +
  rust/pl011/.gitignore  |   2 +
  rust/pl011/Cargo.lock  | 120 +++
  rust/pl011/Cargo.toml  |  66 
  rust/pl011/README.md   |  42 +++
  rust/pl011/build.rs|  44 +++
  rust/pl011/deny.toml   |  57 
  rust/pl011/meson.build |   7 +
  rust/pl011/rustfmt.toml|   1 +


First silly question: how much of this is boiler plate that gets moved the moment that the 
second rust subdirectory is added?




diff --git a/rust/pl011/.cargo/config.toml b/rust/pl011/.cargo/config.toml
new file mode 100644
index 00..241210ffa7
--- /dev/null
+++ b/rust/pl011/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+rustflags = ["-Crelocation-model=pic", "-Ctarget-feature=+crt-static"]


It seems certain that this is not specific to pl011, and will be commot to other rust 
subdirectories.  Or, given the .cargo directory name, is this generated by cargo and 
committed by mistake?




diff --git a/rust/pl011/.gitignore b/rust/pl011/.gitignore
new file mode 100644
index 00..28a02c847f
--- /dev/null
+++ b/rust/pl011/.gitignore
@@ -0,0 +1,2 @@
+target
+src/generated.rs.inc


Is this a symptom of generating files into the source directory and not build 
directory?



diff --git a/rust/pl011/Cargo.lock b/rust/pl011/Cargo.lock
new file mode 100644
index 00..d0fa46f9f5
--- /dev/null
+++ b/rust/pl011/Cargo.lock
@@ -0,0 +1,120 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.


Second silly question: does this really need to be committed to the repository? It 
*appears* to be specific to the host+os-version of the build.  It is certainly very 
specific about versions and checksums...




diff --git a/rust/pl011/Cargo.toml b/rust/pl011/Cargo.toml
new file mode 100644
index 00..db74f2b59f
--- /dev/null
+++ b/rust/pl011/Cargo.toml
@@ -0,0 +1,66 @@
+[package]
+name = "pl011"
+version = "0.1.0"
+edition = "2021"
+authors = ["Manos Pitsidianakis "]
+license = "GPL-2.0 OR GPL-3.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"]
+
+# bilge deps included here to include them with docs
+[dependencies]
+arbitrary-int = { version = "1.2.7" }
+bilge = { version = "0.2.0" }
+bilge-impl = { version = "0.2.0" }


Likewise.


diff --git a/rust/pl011/deny.toml b/rust/pl011/deny.toml
new file mode 100644
index 00..3992380509
--- /dev/null
+++ b/rust/pl011/deny.toml
@@ -0,0 +1,57 @@
+# cargo-deny configuration file
+
+[graph]
+targets = [
+"aarch64-unknown-linux-gnu",
+"x86_64-unknown-linux-gnu",
+"x86_64-apple-darwin",
+"aarch64-apple-darwin",
+"x86_64-pc-windows-gnu",
+"aarch64-pc-windows-gnullvm",
+]


Very much likewise.
Since aarch64-pc-windows-gnullvm is not a host that qemu supports, if this is not 
auto-generated, I am confused.



diff --git a/rust/pl011/rustfmt.toml b/rust/pl011/rustfmt.toml
new file mode 12
index 00..39f97b043b
--- /dev/null
+++ b/rust/pl011/rustfmt.toml
@@ -0,0 +1 @@
+../rustfmt.toml
\ No newline at end of file


Newline.  Also, third silly question: is there a way we can avoid replicating this within 
every rust subdirectory?  E.g. some search path option within one of the build tools?




+++ b/rust/pl011/src/definitions.rs
+++ b/rust/pl011/src/device.rs
+++ b/rust/pl011/src/device_class.rs
+++ b/rust/pl011/src/lib.rs
+++ b/rust/pl011/src/memory_ops.rs


Eek! Actual Rust! Skipping until I am better educated.



diff --git a/rust/pl011/src/generated.rs b/rust/pl011/src/generated.rs
new file mode 100644
index 00..670e7b541d
--- /dev/null
+++ b/rust/pl011/src/generated.rs
@@ -0,0 +1,5 @@
+#[cfg(MESON_GENERATED_RS)]
+include!(concat!(env!("OUT_DIR"), "/generated.rs"));
+
+#[cfg(not(MESON_GENERATED_RS))]
+include!("generated.rs.inc");


Is this indicative of Rust not being prepared to separate source and build directories? 
I'm surprised there would have to be a file in the source to direct the compiler to look 
for a file in the build.



r~



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-18 Thread Peter Maydell
On Tue, 18 Jun 2024 at 10:30, Paolo Bonzini  wrote:
>
> On Tue, Jun 18, 2024 at 11:13 AM Daniel P. Berrangé  
> wrote:
> > I wonder if starting with a device implementation is perhaps the
> > wrong idea, in terms of a practical yet simple first step.
> >
> > As devices go, the pl011 device is simple, but compared to other
> > QOM impls in QEMU, devices are still relatively complex things,
> > especially if we want to write against safe abstraction.
>
> It's true, but I think _some_ complexity provides a better guide as to
> what are the next step.
>
> I think it's clear that they are, not in this order:
> * calling QOM methods (Chardev)
> * implementing QOM objects
> * implementing QOM devices
> ** qdev properties
> ** MemoryRegion callbacks
> * implementing Chardev callbacks
> * general technique for bindings for C structs (Error, QAPI)

Right, this is why I suggested the pl011 as a device: I felt
it provided enough complexity in terms of where it interconnects
to the rest of QEMU to be a realistic way to find out where
the points of difficulty are, without being super complicated
simply as a device. We don't need to have fully worked out
solutions to these things in the first pass, but I agree with
Paolo that we do want to have a clear path forward that says
"this is what we're expecting the solutions to these points
of difficulty to end up looking like and how we plan to get there".

thanks
-- PMM



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-18 Thread Paolo Bonzini
On Tue, Jun 18, 2024 at 11:13 AM Daniel P. Berrangé  wrote:
> I wonder if starting with a device implementation is perhaps the
> wrong idea, in terms of a practical yet simple first step.
>
> As devices go, the pl011 device is simple, but compared to other
> QOM impls in QEMU, devices are still relatively complex things,
> especially if we want to write against safe abstraction.

It's true, but I think _some_ complexity provides a better guide as to
what are the next step.

I think it's clear that they are, not in this order:
* calling QOM methods (Chardev)
* implementing QOM objects
* implementing QOM devices
** qdev properties
** MemoryRegion callbacks
* implementing Chardev callbacks
* general technique for bindings for C structs (Error, QAPI)

> If we did this I think we would not have to give a "free pass"
> for a hackish C-like first Rust impl. We would have something
> designed well from day 1, showing small, but tangible benefits,
> with a path to incrementally broadening the effort.

I don't think it's that easy to have something self contained for a
single submission. Reviewing the build system is a completely
different proposition than reviewing generic-heavy QOM bindings.

Paolo




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-18 Thread Daniel P . Berrangé
On Mon, Jun 17, 2024 at 01:32:54PM +0200, Paolo Bonzini wrote:
> Il lun 17 giu 2024, 10:59 Manos Pitsidianakis <
> manos.pitsidiana...@linaro.org> ha scritto:
> 
> > >qdev_define_type!(c"test-device", TestDevice);
> > >impl ObjectImpl for TestDevice {}
> > >impl DeviceImpl for TestDevice {}
> > >
> > >fn main() {
> > >let d = TestDevice::new();
> > >d.cold_reset();
> > >}
> > >
> > >Of course the code makes no sense but it's a start.
> >
> > Let's not rush into making interfaces without the need for them arising
> > first. It's easy to wander off into bikeshedding territory; case in
> > point, there has been little discussion on the code of this RFC and much
> > more focus on hypotheticals.
> >
> 
> I see your point but I think it's important to understand the road ahead of
> us.
> 
> Knowing that we can build and maintain a usable (does not have to be
> perfect) interface to QOM is important, and in fact it's already useful for
> the pl011 device's chardev. It's also important to play with more advanced
> usage of the language to ascertain what features of the language will be
> useful; for example, my current implementation uses generic associated
> types which are not available on Debian Bookworm—it should be easy to
> remove them but if I am wrong that's also a data point, and an important
> one.
> 
> Don't get me wrong: *for this first device* only, it makes a lot of sense
> to have a very C-ish implementation. It lets us sort out the build system
> integration, tackle idiomatic bindings one piece at a time, and is easier
> to review than Marc-André's approach of building the whole QAPI bindings.
> But at the same time, I don't consider a C-ish device better just because
> it's written in Rust: as things stand your code has all the disadvantages
> of C and all the disadvantages of Rust. What makes it (extremely) valuable
> is that your code can lead us along the path towards reaping the advantages
> of Rust.

I wonder if starting with a device implementation is perhaps the
wrong idea, in terms of a practical yet simple first step.

As devices go, the pl011 device is simple, but compared to other
QOM impls in QEMU, devices are still relatively complex things,
especially if we want to write against safe abstraction.

How about we go simpler still, and focus on one of the object
backends. For example, the RNG backend interface is practically
the most trivial QOM impl we can do in QEMU. It has one virtual
method that needs to be implemented, which is passed a callback
to receive entropy, and one native method to call to indicate
completion.

Providing a safe Rust abstraction for implementing an RNG
backend looks like a much quicker proposition that a safe
abstraction for implementing a device. The various RNG impls
have a few places where they touch other QEMU code (rng-builtin
uses qemu_bh, rng-egd lightly touches chardev APIs, rng-random
touches main loop FD handlers). Each of those things though, are
small & useful API problems to look it solving.

If we did this I think we would not have to give a "free pass"
for a hackish C-like first Rust impl. We would have something
designed well from day 1, showing small, but tangible benefits,
with a path to incrementally broadening the effort.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Paolo Bonzini
Il lun 17 giu 2024, 23:45 Manos Pitsidianakis
 ha scritto:
> Secondly, are you implying that these callbacks are not operated under
> the BQL?

No, I'm implying that if you had the following nested calls:

 unsafe read callback receives the opaque point
   -> cast to &mut to call safe read callback
 -> chardev function accessing the opaque value
   -> unsafe chardev callback receives the opaque pointer
 -> cast to & or &mut to call safe chardev callback

Then you would violate the Rust invariant that there can only be one
active reference at a single time if it is &mut. The only exception is
that you can create an &mut UnsafeCell for an active
&UnsafeCell.

It doesn't matter if this cannot happen because of invariants in the
QEMU code. If you are writing safe Rust, every cast to &mut requires
very strong justification. The way you do it instead is to use
RefCell, and borrow_mut() instead of casting to &mut. This way, at
least, the invariant is checked at runtime.

And in fact this _can_ happen. I hadn't checked until now because I
was mostly worried about the conceptual problem, not any specific way
undefined behavior can happen. But here it is:

PL011State::read takes &mut
  -> qemu_chr_fe_accept_input
-> mux_chr_accept_input
  -> pl011_can_receive
-> creates & which is undefined behavior

You probably can write a 20 lines test case in pure Rust that miri
complains about.

Should we make it a requirement for v3, that all callback methods in
PL011State (read, write, can_receive, receive, event) take a &self and
achieve interior mutability through RefCell? Probably not, a comment
is enough even though technically this is _not_ valid Rust. But it is
a high priority task after the initial commit.

> Just say this directly instead of writing all these amounts of text

I said in the first review that the state should be behind a RefCell.

https://lore.kernel.org/qemu-devel/CABgObfY8BS0yCw2CxgDQTBA4np9BZgGJF3N=t6eoBcdACAE=n...@mail.gmail.com/

> Finally, this is Rust code. You cannot turn off the type system, you
> cannot turn off the borrow checker, you can only go around creating new
> types and references out of raw memory addresses and tell the compiler
> 'trust me on this'

I am sorry if this sounds condescending. But this is _exactly_ what
I'm complaining about: that there is too much trust placed in the
programmer.

Converting from * to & does not turn off the borrow checker, but still
you cannot trust anymore what the borrow checker says; and that's why
you do it inside an abstraction, not in each and every callback of
each and every device. This is what Marc-André did for QAPI; and he
probably erred in the other direction for a PoC, but we _must_ agree
that something as complete as his work is the direction that we _have_
to take.

Again: I am sorry that you feel this way about my remark, because I
thought I had only praised your work. I didn't think I was being
condescending or dismissing. But I am worried that without the proper
abstractions this is going to be a technical debt magnet with only
marginal benefits over C.

And frankly I am saying this from experience. Check out CVE-2019-18960
which was an out of bounds access in Firecracker caused by not using
proper abstractions for DMA. And that's in a 100% Rust code base.
Since we're starting from and interfacing with C it's only going to be
worse; skimping on abstractions is simply something that we cannot
afford.

It's also the way Linux is introducing Rust in the code base. Whenever
something needs access to C functionality they introduce bindings to
it. It's slower, but it's sustainable.

> Ignoring that misses the entire point of Rust. The
> statement 'this is not Rust code but as good as C' is dishonest and
> misguided. Check for example the source code of the nix crate, which
> exposes libc and various POSIX/*nix APIs. Is it the same as C and not
> Rust code?

That's exactly my point. Libc provides mostly unsafe functions, which
is on the level of what bindgen generates. Other crates on top provide
*safe abstractions* such as nix's Dir
(https://docs.rs/nix/0.29.0/nix/dir/struct.Dir.html). If possible,
leaf crates use safe Rust (nix), and avoid unsafe (libc) as much as
possible.

Instead you're using the unsafe functions in the device itself. It's
missing an equivalent of nix.

> If you have specific scenarios in mind where such things exist in the
> code and end up doing invalid behavior please be kind and write them
> down explicitly and demonstrate them on code review.

It doesn't matter whether they exist or not. The point of Rust is that
the type system ensures that these invalid behaviors are caught either
at compile time or (with RefCell) at run time. As things stand, your
code cannot catch them and the language provides a false sense of
security.

On the other hand, I want to be clear agin that this is not a problem
at all—but only as long as we agree that it's not the desired final
state

> This approach

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Paolo Bonzini
On Tue, Jun 18, 2024 at 1:33 AM Pierrick Bouvier
 wrote:
>
> On 6/17/24 14:04, Manos Pitsidianakis wrote:
> > On Mon, 17 Jun 2024 17:32, Paolo Bonzini  wrote:
> >> On Mon, Jun 17, 2024 at 4:04 PM Manos Pitsidianakis
> >>  wrote:
> >>> I respectfully disagree and recommend taking another look at the code.
> >>>
> >>> The device actually performs all logic in non-unsafe methods and is
> >>> typed instead of operating on raw integers as fields/state. The C stuff
> >>> is the FFI boundary calls which you cannot avoid; they are the same
> >>> things you'd wrap under these bindings we're talking about.
> >>
> >> Indeed, but the whole point is that the bindings wrap unsafe code in
> >> such a way that the safety invariants hold. Not doing this, especially
> >> for a device that does not do DMA (so that there are very few ways
> >> that things can go wrong in the first place), runs counter to the
> >> whole philosophy of Rust.
> >>
> >> For example, you have:
> >>
> >> pub fn realize(&mut self) {
> >> 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::(),
> >> core::ptr::null_mut(),
> >> true,
> >> );
> >> }
> >> }
> >>
> >> where you are implicitly relying on the fact that pl011_can_receive(),
> >> pl011_receive(), pl011_event() are never called from the
> >> MemoryRegionOps read() and write() callbacks. Otherwise you'd have two
> >> mutable references at the same time, one as an argument to the
> >> callbacks:
> >>
> >>pub fn read(&mut self, offset: hwaddr, ...
> >>
> >> and one from e.g. "state.as_mut().put_fifo()" in pl011_receive().
> >>
> >> This is not Rust code. It makes no attempt at enforcing the whole
> >> "shared XOR mutable" which is the basis of Rust's reference semantics.
> >> In other words, this is as safe as C code---sure, it can use nice
> >> abstractions for register access, it has "unsafe" added in front of
> >> pointer dereferences, but it is not safe.
> >>
> >> Again, I'm not saying it's a bad first step. It's *awesome* if we
> >> treat it as what it is: a guide towards providing safe bindings
> >> between Rust and C (which often implies them being idiomatic). But if
> >> we don't accept this, if there is no plan to make the code safe, it is
> >> a potential huge source of technical debt.
> >>
> >>> QEMU calls the device's FFI callbacks with its pointer and arguments,
> >>> the pointer gets dereferenced to the actual Rust type which qemu
> >>> guarantees is valid, then the Rust struct's methods are called to handle
> >>> each functionality. There is nothing actually unsafe here, assuming
> >>> QEMU's invariants and code are correct.
> >>
> >> The same can be said of C code, can't it? There is nothing unsafe in C
> >> code, assuming there are no bugs...
> >
> > Paolo, first please tone down your condescending tone, it's incredibly
> > offensive. I'm honestly certain this is not on purpose otherwise I'd not
> > engage at all.
>
> The best compliment you had was "I'm not saying it's a bad first step",
> and I would say this differently: It's a great first step!

Don't quote me out of context; I said It's an "awesome" first step,
though I qualified that we should treat it as "a guide towards
providing safe bindings between Rust and C". That is, as long as we
agree that it is not production quality code. Which it doesn't have to
be!

> We should have a first version where we stick to the C API, with all the
> Rust code being as Rusty as possible: benefit from typed enums, error
> handling, bounds checking and other nice things.
>
> It's useless to iterate/debate for two years on the list before landing
> something upstream. We can start with this, have one or two devices that
> use this build system, and then focus on designing a good interface for
> this.

I never said that I want perfection before landing upstream. I want _a path_.

When I read "there was consensus in the community call that we won't
be writing Rust APIs for internal C QEMU interfaces; or at least,
that's not the goal"[1], then sorry but I think that it's better to
stick with C.

On the other hand, if there is a path towards proper, maintainable
Rust, then I am even okay even with committing something that
technically contains undefined behavior.

[1] https://lore.kernel.org/qemu-devel/ez270.x96k6aeu0...@linaro.org/

> As I mentioned in my previous answer, this device already makes a good
> progress: it eliminates a whole class of memory errors, and the only
> issue brought by unsafe code is concurrency issues. And this should be
> our focus once we get the build infrastructure done!

Let's not exaggerate the benefits: no pointers were converted to RAII
(Box<> or Rc<>) in the course of writing the Rust co

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Pierrick Bouvier

On 6/17/24 14:04, Manos Pitsidianakis wrote:

On Mon, 17 Jun 2024 17:32, Paolo Bonzini  wrote:

On Mon, Jun 17, 2024 at 4:04 PM Manos Pitsidianakis
 wrote:

I respectfully disagree and recommend taking another look at the code.

The device actually performs all logic in non-unsafe methods and is
typed instead of operating on raw integers as fields/state. The C stuff
is the FFI boundary calls which you cannot avoid; they are the same
things you'd wrap under these bindings we're talking about.


Indeed, but the whole point is that the bindings wrap unsafe code in
such a way that the safety invariants hold. Not doing this, especially
for a device that does not do DMA (so that there are very few ways
that things can go wrong in the first place), runs counter to the
whole philosophy of Rust.

For example, you have:

pub fn realize(&mut self) {
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::(),
core::ptr::null_mut(),
true,
);
}
}

where you are implicitly relying on the fact that pl011_can_receive(),
pl011_receive(), pl011_event() are never called from the
MemoryRegionOps read() and write() callbacks. Otherwise you'd have two
mutable references at the same time, one as an argument to the
callbacks:

   pub fn read(&mut self, offset: hwaddr, ...

and one from e.g. "state.as_mut().put_fifo()" in pl011_receive().

This is not Rust code. It makes no attempt at enforcing the whole
"shared XOR mutable" which is the basis of Rust's reference semantics.
In other words, this is as safe as C code---sure, it can use nice
abstractions for register access, it has "unsafe" added in front of
pointer dereferences, but it is not safe.

Again, I'm not saying it's a bad first step. It's *awesome* if we
treat it as what it is: a guide towards providing safe bindings
between Rust and C (which often implies them being idiomatic). But if
we don't accept this, if there is no plan to make the code safe, it is
a potential huge source of technical debt.


QEMU calls the device's FFI callbacks with its pointer and arguments,
the pointer gets dereferenced to the actual Rust type which qemu
guarantees is valid, then the Rust struct's methods are called to handle
each functionality. There is nothing actually unsafe here, assuming
QEMU's invariants and code are correct.


The same can be said of C code, can't it? There is nothing unsafe in C
code, assuming there are no bugs...


Paolo, first please tone down your condescending tone, it's incredibly
offensive. I'm honestly certain this is not on purpose otherwise I'd not
engage at all.


The best compliment you had was "I'm not saying it's a bad first step", 
and I would say this differently: It's a great first step!


We should have a first version where we stick to the C API, with all the 
Rust code being as Rusty as possible: benefit from typed enums, error 
handling, bounds checking and other nice things.


It's useless to iterate/debate for two years on the list before landing 
something upstream. We can start with this, have one or two devices that 
use this build system, and then focus on designing a good interface for 
this.




Secondly, are you implying that these callbacks are not operated under
the BQL? I'm not seeing the C UART devices using mutexes. If they are
not running under the BQL, then gladly we add mutexes, big deal. Just
say this directly instead of writing all these amounts of text. If it's
true I'd just accept it and move on with a new iteration. Isn't that the
point of code review? It is really that simple. Why not do this right
away? I'm frankly puzzled.



As I mentioned in my previous answer, this device already makes a good 
progress: it eliminates a whole class of memory errors, and the only 
issue brought by unsafe code is concurrency issues. And this should be 
our focus once we get the build infrastructure done!



Finally, this is Rust code. You cannot turn off the type system, you
cannot turn off the borrow checker, you can only go around creating new
types and references out of raw memory addresses and tell the compiler
'trust me on this'. Ignoring that misses the entire point of Rust. The
statement 'this is not Rust code but as good as C' is dishonest and
misguided. Check for example the source code of the nix crate, which
exposes libc and various POSIX/*nix APIs. Is it the same as C and not
Rust code?

If you have specific scenarios in mind where such things exist in the
code and end up doing invalid behavior please be kind and write them
down explicitly and demonstrate them on code review. This approach of
'yes but no' is not constructive because it is not addressing any
specific problems directly. Instead it comes out as vague dismissive FUD
and I'm sure that is no

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Pierrick Bouvier

On 6/17/24 07:32, Paolo Bonzini wrote:

On Mon, Jun 17, 2024 at 4:04 PM Manos Pitsidianakis
 wrote:

I respectfully disagree and recommend taking another look at the code.

The device actually performs all logic in non-unsafe methods and is
typed instead of operating on raw integers as fields/state. The C stuff
is the FFI boundary calls which you cannot avoid; they are the same
things you'd wrap under these bindings we're talking about.


Indeed, but the whole point is that the bindings wrap unsafe code in
such a way that the safety invariants hold. Not doing this, especially
for a device that does not do DMA (so that there are very few ways
that things can go wrong in the first place), runs counter to the
whole philosophy of Rust.



You are raising an interesting point, and should be a central discussion 
when designing the future Rust API for this subsystem.
It may not be intuitive to people that even a code without any unsafe 
section could still call code in a sequence that will violate some 
invariants, and break Rust rules.
IMHO, this is one of the big challenge with the Rust/C interfacing, 
including for Linux.


But it's *not yet* the goal of this series. First, we should see how to 
build one device (I would even like to see a second, to factorize all 
the boilerplate), and then, focus on which interface we want to have to 
make it really better than the C version.



For example, you have:

 pub fn realize(&mut self) {
 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::(),
 core::ptr::null_mut(),
 true,
 );
 }
 }

where you are implicitly relying on the fact that pl011_can_receive(),
pl011_receive(), pl011_event() are never called from the
MemoryRegionOps read() and write() callbacks. Otherwise you'd have two
mutable references at the same time, one as an argument to the
callbacks:

pub fn read(&mut self, offset: hwaddr, ...

and one from e.g. "state.as_mut().put_fifo()" in pl011_receive().

This is not Rust code. It makes no attempt at enforcing the whole
"shared XOR mutable" which is the basis of Rust's reference semantics.
In other words, this is as safe as C code---sure, it can use nice
abstractions for register access, it has "unsafe" added in front of
pointer dereferences, but it is not safe.



I think that Manos did a great amount of work to reduce the use of 
unsafe code. Basically, he wrote the device as Rusty as possible, while 
still using the QEMU C API part that is inevitable today.


In more, given the current design, yes some race conditions are possible 
(depends on how QEMU calls callbacks installed), but a whole class of 
problems is still eliminated.


From the start of this series, it was precised that focus was on build 
system, and it seemed to me that we shifted on the hot debate of "How to 
interface with C code?".



Again, I'm not saying it's a bad first step. It's *awesome* if we
treat it as what it is: a guide towards providing safe bindings
between Rust and C (which often implies them being idiomatic). But if
we don't accept this, if there is no plan to make the code safe, it is
a potential huge source of technical debt.



I agree, it should be the next direction after a first device was 
written: How to remove almost all usage of unsafe code and maintain good 
invariants in the API?


While talking about idiomatic, Rust tends to favor message passing to 
memory share when it comes to concurrency (and IMHO, it's the right 
thing). And it's definitely now how QEMU is architected at this time.


With extra locking, we should be able to have a first correct interface 
that offers strong guarantees, and we can then work on making it faster 
with concurrency.



QEMU calls the device's FFI callbacks with its pointer and arguments,
the pointer gets dereferenced to the actual Rust type which qemu
guarantees is valid, then the Rust struct's methods are called to handle
each functionality. There is nothing actually unsafe here, assuming
QEMU's invariants and code are correct.


The same can be said of C code, can't it? There is nothing unsafe in C
code, assuming there are no bugs...



Not the same, you still get other compile/runtime guarantees:
- strong typed enums, so no case is forgotten
- good error handling
- safe type conversions
- bound check of fifo access

The only open issue by calling unsafe code in this context is related to 
(potential) concurrency. If a first step to have a good Rust API is to 
run everything under a lock, there is good chance you already started to 
design the device in the right way to support real concurrency later, so 
it's still useful.


Pierrick


Paolo



I think we're actually in a great position. We have a PoC from Marc-André,
plus the

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Manos Pitsidianakis

On Mon, 17 Jun 2024 17:32, Paolo Bonzini  wrote:

On Mon, Jun 17, 2024 at 4:04 PM Manos Pitsidianakis
 wrote:

I respectfully disagree and recommend taking another look at the code.

The device actually performs all logic in non-unsafe methods and is
typed instead of operating on raw integers as fields/state. The C stuff
is the FFI boundary calls which you cannot avoid; they are the same
things you'd wrap under these bindings we're talking about.


Indeed, but the whole point is that the bindings wrap unsafe code in
such a way that the safety invariants hold. Not doing this, especially
for a device that does not do DMA (so that there are very few ways
that things can go wrong in the first place), runs counter to the
whole philosophy of Rust.

For example, you have:

   pub fn realize(&mut self) {
   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::(),
   core::ptr::null_mut(),
   true,
   );
   }
   }

where you are implicitly relying on the fact that pl011_can_receive(),
pl011_receive(), pl011_event() are never called from the
MemoryRegionOps read() and write() callbacks. Otherwise you'd have two
mutable references at the same time, one as an argument to the
callbacks:

  pub fn read(&mut self, offset: hwaddr, ...

and one from e.g. "state.as_mut().put_fifo()" in pl011_receive().

This is not Rust code. It makes no attempt at enforcing the whole
"shared XOR mutable" which is the basis of Rust's reference semantics.
In other words, this is as safe as C code---sure, it can use nice
abstractions for register access, it has "unsafe" added in front of
pointer dereferences, but it is not safe.

Again, I'm not saying it's a bad first step. It's *awesome* if we
treat it as what it is: a guide towards providing safe bindings
between Rust and C (which often implies them being idiomatic). But if
we don't accept this, if there is no plan to make the code safe, it is
a potential huge source of technical debt.


QEMU calls the device's FFI callbacks with its pointer and arguments,
the pointer gets dereferenced to the actual Rust type which qemu
guarantees is valid, then the Rust struct's methods are called to handle
each functionality. There is nothing actually unsafe here, assuming
QEMU's invariants and code are correct.


The same can be said of C code, can't it? There is nothing unsafe in C
code, assuming there are no bugs...


Paolo, first please tone down your condescending tone, it's incredibly 
offensive. I'm honestly certain this is not on purpose otherwise I'd not 
engage at all.


Secondly, are you implying that these callbacks are not operated under 
the BQL? I'm not seeing the C UART devices using mutexes. If they are 
not running under the BQL, then gladly we add mutexes, big deal. Just 
say this directly instead of writing all these amounts of text. If it's 
true I'd just accept it and move on with a new iteration. Isn't that the 
point of code review? It is really that simple. Why not do this right 
away? I'm frankly puzzled.


Finally, this is Rust code. You cannot turn off the type system, you 
cannot turn off the borrow checker, you can only go around creating new 
types and references out of raw memory addresses and tell the compiler 
'trust me on this'. Ignoring that misses the entire point of Rust. The 
statement 'this is not Rust code but as good as C' is dishonest and 
misguided. Check for example the source code of the nix crate, which 
exposes libc and various POSIX/*nix APIs. Is it the same as C and not 
Rust code?


If you have specific scenarios in mind where such things exist in the 
code and end up doing invalid behavior please be kind and write them 
down explicitly and demonstrate them on code review. This approach of 
'yes but no' is not constructive because it is not addressing any 
specific problems directly. Instead it comes out as vague dismissive FUD 
and I'm sure that is not what you or anyone else wants.


Please take some time to understand my POV here, it'd help both of us 
immensely.


Sincerely thank you in advance,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Paolo Bonzini
On Mon, Jun 17, 2024 at 4:04 PM Manos Pitsidianakis
 wrote:
> I respectfully disagree and recommend taking another look at the code.
>
> The device actually performs all logic in non-unsafe methods and is
> typed instead of operating on raw integers as fields/state. The C stuff
> is the FFI boundary calls which you cannot avoid; they are the same
> things you'd wrap under these bindings we're talking about.

Indeed, but the whole point is that the bindings wrap unsafe code in
such a way that the safety invariants hold. Not doing this, especially
for a device that does not do DMA (so that there are very few ways
that things can go wrong in the first place), runs counter to the
whole philosophy of Rust.

For example, you have:

pub fn realize(&mut self) {
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::(),
core::ptr::null_mut(),
true,
);
}
}

where you are implicitly relying on the fact that pl011_can_receive(),
pl011_receive(), pl011_event() are never called from the
MemoryRegionOps read() and write() callbacks. Otherwise you'd have two
mutable references at the same time, one as an argument to the
callbacks:

   pub fn read(&mut self, offset: hwaddr, ...

and one from e.g. "state.as_mut().put_fifo()" in pl011_receive().

This is not Rust code. It makes no attempt at enforcing the whole
"shared XOR mutable" which is the basis of Rust's reference semantics.
In other words, this is as safe as C code---sure, it can use nice
abstractions for register access, it has "unsafe" added in front of
pointer dereferences, but it is not safe.

Again, I'm not saying it's a bad first step. It's *awesome* if we
treat it as what it is: a guide towards providing safe bindings
between Rust and C (which often implies them being idiomatic). But if
we don't accept this, if there is no plan to make the code safe, it is
a potential huge source of technical debt.

> QEMU calls the device's FFI callbacks with its pointer and arguments,
> the pointer gets dereferenced to the actual Rust type which qemu
> guarantees is valid, then the Rust struct's methods are called to handle
> each functionality. There is nothing actually unsafe here, assuming
> QEMU's invariants and code are correct.

The same can be said of C code, can't it? There is nothing unsafe in C
code, assuming there are no bugs...

Paolo

> >
> >I think we're actually in a great position. We have a PoC from Marc-André,
> >plus the experience of glib-rs (see below), that shows us that our goal of
> >idiomatic bindings is doable; and a complementary PoC from you that will
> >guide us and let us reach it in little steps. The first 90% of the work is
> >done, now we only have to do the second 90%... :) but then we can open the
> >floodgates for Rust code in QEMU.
> >
> >For what it's worth, in my opinion looking at glib-rs for inspiration is
> >> a bad idea, because that project has to support an immutable public
> >> interface (glib) while we do not.
> >>
> >
> >glib-rs includes support for GObject, which was itself an inspiration for
> >QOM (with differences, granted).
> >
> >There are a lot of libraries that we can take inspiration from: in addition
> >to glib-rs, zbus has an interesting approach to
> >serialization/deserialization for example that could inform future work on
> >QAPI. It's not a coincidence that these libraries integrate with more
> >traditional C code, because we are doing the same. Rust-vmm crates will
> >also become an interesting topic sooner or later.
> >
> >There's more to discuss about this topic which I am open to continuing
> >> on IRC instead!
> >>
> >
> >Absolutely, I will try to post code soonish and also review the build
> >system integration.
> >
> >Thanks,
> >
> >Paolo
> >
> >
> >> -- Manos Pitsidianakis
> >> Emulation and Virtualization Engineer at Linaro Ltd
> >>
> >> >
> >> >One thing that would be very useful is to have an Error
> >> >implementation. Looking at what Marc-André did for Error*
> >> >(
> >> https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/20210907121943.3498701-13-marcandre.lur...@redhat.com/
> >> ),
> >> >his precise implementation relies on his code to go back and forth
> >> >between Rust representation, borrowed C object with Rust bindings and
> >> >owned C object with Rust bindings. But I think we can at least have
> >> >something like this:
> >> >
> >> >// qemu::Error
> >> >pub struct Error {
> >> >msg: String,
> >> >/// Appends the print string of the error to the msg if not None
> >> >cause: Option>,
> >> >location: Option<(String, u32)>
> >> >}
> >> >
> >> >impl std::error::Error for Error { ... }
> >> >
> >> >impl Error {
> >> >  ...
> >> >  fn into_c_error(self) -> *const bindings::Er

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Manos Pitsidianakis

On Mon, 17 Jun 2024 14:32, Paolo Bonzini  wrote:

Il lun 17 giu 2024, 10:59 Manos Pitsidianakis <
manos.pitsidiana...@linaro.org> ha scritto:


>qdev_define_type!(c"test-device", TestDevice);
>impl ObjectImpl for TestDevice {}
>impl DeviceImpl for TestDevice {}
>
>fn main() {
>let d = TestDevice::new();
>d.cold_reset();
>}
>
>Of course the code makes no sense but it's a start.

Let's not rush into making interfaces without the need for them arising
first. It's easy to wander off into bikeshedding territory; case in
point, there has been little discussion on the code of this RFC and much
more focus on hypotheticals.



I see your point but I think it's important to understand the road ahead of
us.

Knowing that we can build and maintain a usable (does not have to be
perfect) interface to QOM is important, and in fact it's already useful for
the pl011 device's chardev. It's also important to play with more advanced
usage of the language to ascertain what features of the language will be
useful; for example, my current implementation uses generic associated
types which are not available on Debian Bookworm—it should be easy to
remove them but if I am wrong that's also a data point, and an important
one.

Don't get me wrong: *for this first device* only, it makes a lot of sense
to have a very C-ish implementation. It lets us sort out the build system
integration, tackle idiomatic bindings one piece at a time, and is easier
to review than Marc-André's approach of building the whole QAPI bindings.
But at the same time, I don't consider a C-ish device better just because
it's written in Rust: as things stand your code has all the disadvantages
of C and all the disadvantages of Rust. What makes it (extremely) valuable
is that your code can lead us along the path towards reaping the advantages
of Rust.


I respectfully disagree and recommend taking another look at the code.

The device actually performs all logic in non-unsafe methods and is 
typed instead of operating on raw integers as fields/state. The C stuff 
is the FFI boundary calls which you cannot avoid; they are the same 
things you'd wrap under these bindings we're talking about.


QEMU calls the device's FFI callbacks with its pointer and arguments, 
the pointer gets dereferenced to the actual Rust type which qemu 
guarantees is valid, then the Rust struct's methods are called to handle 
each functionality. There is nothing actually unsafe here, assuming 
QEMU's invariants and code are correct.




I think we're actually in a great position. We have a PoC from Marc-André,
plus the experience of glib-rs (see below), that shows us that our goal of
idiomatic bindings is doable; and a complementary PoC from you that will
guide us and let us reach it in little steps. The first 90% of the work is
done, now we only have to do the second 90%... :) but then we can open the
floodgates for Rust code in QEMU.

For what it's worth, in my opinion looking at glib-rs for inspiration is

a bad idea, because that project has to support an immutable public
interface (glib) while we do not.



glib-rs includes support for GObject, which was itself an inspiration for
QOM (with differences, granted).

There are a lot of libraries that we can take inspiration from: in addition
to glib-rs, zbus has an interesting approach to
serialization/deserialization for example that could inform future work on
QAPI. It's not a coincidence that these libraries integrate with more
traditional C code, because we are doing the same. Rust-vmm crates will
also become an interesting topic sooner or later.

There's more to discuss about this topic which I am open to continuing

on IRC instead!



Absolutely, I will try to post code soonish and also review the build
system integration.

Thanks,

Paolo



-- Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd

>
>One thing that would be very useful is to have an Error
>implementation. Looking at what Marc-André did for Error*
>(
https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/20210907121943.3498701-13-marcandre.lur...@redhat.com/
),
>his precise implementation relies on his code to go back and forth
>between Rust representation, borrowed C object with Rust bindings and
>owned C object with Rust bindings. But I think we can at least have
>something like this:
>
>// qemu::Error
>pub struct Error {
>msg: String,
>/// Appends the print string of the error to the msg if not None
>cause: Option>,
>location: Option<(String, u32)>
>}
>
>impl std::error::Error for Error { ... }
>
>impl Error {
>  ...
>  fn into_c_error(self) -> *const bindings::Error { ... }
>}
>
>// qemu::Result
>type Result = Result;
>
>which can be implemented without too much code. This way any "bool
>f(..., Error *)" function (example: realize :)) could be implemented
>as returning qemu::Result<()>.






Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Paolo Bonzini
Il lun 17 giu 2024, 10:59 Manos Pitsidianakis <
manos.pitsidiana...@linaro.org> ha scritto:

> >qdev_define_type!(c"test-device", TestDevice);
> >impl ObjectImpl for TestDevice {}
> >impl DeviceImpl for TestDevice {}
> >
> >fn main() {
> >let d = TestDevice::new();
> >d.cold_reset();
> >}
> >
> >Of course the code makes no sense but it's a start.
>
> Let's not rush into making interfaces without the need for them arising
> first. It's easy to wander off into bikeshedding territory; case in
> point, there has been little discussion on the code of this RFC and much
> more focus on hypotheticals.
>

I see your point but I think it's important to understand the road ahead of
us.

Knowing that we can build and maintain a usable (does not have to be
perfect) interface to QOM is important, and in fact it's already useful for
the pl011 device's chardev. It's also important to play with more advanced
usage of the language to ascertain what features of the language will be
useful; for example, my current implementation uses generic associated
types which are not available on Debian Bookworm—it should be easy to
remove them but if I am wrong that's also a data point, and an important
one.

Don't get me wrong: *for this first device* only, it makes a lot of sense
to have a very C-ish implementation. It lets us sort out the build system
integration, tackle idiomatic bindings one piece at a time, and is easier
to review than Marc-André's approach of building the whole QAPI bindings.
But at the same time, I don't consider a C-ish device better just because
it's written in Rust: as things stand your code has all the disadvantages
of C and all the disadvantages of Rust. What makes it (extremely) valuable
is that your code can lead us along the path towards reaping the advantages
of Rust.

I think we're actually in a great position. We have a PoC from Marc-André,
plus the experience of glib-rs (see below), that shows us that our goal of
idiomatic bindings is doable; and a complementary PoC from you that will
guide us and let us reach it in little steps. The first 90% of the work is
done, now we only have to do the second 90%... :) but then we can open the
floodgates for Rust code in QEMU.

For what it's worth, in my opinion looking at glib-rs for inspiration is
> a bad idea, because that project has to support an immutable public
> interface (glib) while we do not.
>

glib-rs includes support for GObject, which was itself an inspiration for
QOM (with differences, granted).

There are a lot of libraries that we can take inspiration from: in addition
to glib-rs, zbus has an interesting approach to
serialization/deserialization for example that could inform future work on
QAPI. It's not a coincidence that these libraries integrate with more
traditional C code, because we are doing the same. Rust-vmm crates will
also become an interesting topic sooner or later.

There's more to discuss about this topic which I am open to continuing
> on IRC instead!
>

Absolutely, I will try to post code soonish and also review the build
system integration.

Thanks,

Paolo


> -- Manos Pitsidianakis
> Emulation and Virtualization Engineer at Linaro Ltd
>
> >
> >One thing that would be very useful is to have an Error
> >implementation. Looking at what Marc-André did for Error*
> >(
> https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/20210907121943.3498701-13-marcandre.lur...@redhat.com/
> ),
> >his precise implementation relies on his code to go back and forth
> >between Rust representation, borrowed C object with Rust bindings and
> >owned C object with Rust bindings. But I think we can at least have
> >something like this:
> >
> >// qemu::Error
> >pub struct Error {
> >msg: String,
> >/// Appends the print string of the error to the msg if not None
> >cause: Option>,
> >location: Option<(String, u32)>
> >}
> >
> >impl std::error::Error for Error { ... }
> >
> >impl Error {
> >  ...
> >  fn into_c_error(self) -> *const bindings::Error { ... }
> >}
> >
> >// qemu::Result
> >type Result = Result;
> >
> >which can be implemented without too much code. This way any "bool
> >f(..., Error *)" function (example: realize :)) could be implemented
> >as returning qemu::Result<()>.
>
>


Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-17 Thread Manos Pitsidianakis

On Fri, 14 Jun 2024 20:50, Paolo Bonzini  wrote:

On Fri, Jun 14, 2024 at 9:04 AM Manos Pitsidianakis
 wrote:


On Thu, 13 Jun 2024 23:57, Paolo Bonzini  wrote:
>On Thu, Jun 13, 2024 at 11:16 AM Daniel P. Berrangé  
wrote:
>> I guess there's a balance to be had somewhere on the spectrum between doing
>> everything against the raw C binding, vs everything against a perfectly
>> idiomatic Rust API wrapping the C bniding. The latter might be the ideal,
>> but from a pragmmatic POV I doubt we want the barrier to entry to be that
>> high.
>
>Yes, I agree. I guess we could make things work step by step, even
>committing something that only focuses on the build system like
>Manos's work (I'll review it).
>
>I can try to look at the basic QOM interface.
>
>Manos, can you create a page on the wiki? Something like
>https://wiki.qemu.org/Features/Meson.


Certainly! Just to make sure I understood correctly, you mean a wiki
page describing how things work and tracking the progress?

I added https://wiki.qemu.org/Features/Meson/Rust


I moved it to https://wiki.qemu.org/Features/Rust/Meson :) and wrote
https://wiki.qemu.org/Features/Rust/QOM. I got to the point where at
least this compiles:

qdev_define_type!(c"test-device", TestDevice);
impl ObjectImpl for TestDevice {}
impl DeviceImpl for TestDevice {}

fn main() {
   let d = TestDevice::new();
   d.cold_reset();
}

Of course the code makes no sense but it's a start.


Let's not rush into making interfaces without the need for them arising 
first. It's easy to wander off into bikeshedding territory; case in 
point, there has been little discussion on the code of this RFC and much 
more focus on hypotheticals.


For what it's worth, in my opinion looking at glib-rs for inspiration is 
a bad idea, because that project has to support an immutable public 
interface (glib) while we do not.


There's more to discuss about this topic which I am open to continuing 
on IRC instead!


-- Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd



One thing that would be very useful is to have an Error
implementation. Looking at what Marc-André did for Error*
(https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/20210907121943.3498701-13-marcandre.lur...@redhat.com/),
his precise implementation relies on his code to go back and forth
between Rust representation, borrowed C object with Rust bindings and
owned C object with Rust bindings. But I think we can at least have
something like this:

// qemu::Error
pub struct Error {
   msg: String,
   /// Appends the print string of the error to the msg if not None
   cause: Option>,
   location: Option<(String, u32)>
}

impl std::error::Error for Error { ... }

impl Error {
 ...
 fn into_c_error(self) -> *const bindings::Error { ... }
}

// qemu::Result
type Result = Result;

which can be implemented without too much code. This way any "bool
f(..., Error *)" function (example: realize :)) could be implemented
as returning qemu::Result<()>.




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-14 Thread Paolo Bonzini
On Fri, Jun 14, 2024 at 9:04 AM Manos Pitsidianakis
 wrote:
>
> On Thu, 13 Jun 2024 23:57, Paolo Bonzini  wrote:
> >On Thu, Jun 13, 2024 at 11:16 AM Daniel P. Berrangé  
> >wrote:
> >> I guess there's a balance to be had somewhere on the spectrum between doing
> >> everything against the raw C binding, vs everything against a perfectly
> >> idiomatic Rust API wrapping the C bniding. The latter might be the ideal,
> >> but from a pragmmatic POV I doubt we want the barrier to entry to be that
> >> high.
> >
> >Yes, I agree. I guess we could make things work step by step, even
> >committing something that only focuses on the build system like
> >Manos's work (I'll review it).
> >
> >I can try to look at the basic QOM interface.
> >
> >Manos, can you create a page on the wiki? Something like
> >https://wiki.qemu.org/Features/Meson.
>
>
> Certainly! Just to make sure I understood correctly, you mean a wiki
> page describing how things work and tracking the progress?
>
> I added https://wiki.qemu.org/Features/Meson/Rust

I moved it to https://wiki.qemu.org/Features/Rust/Meson :) and wrote
https://wiki.qemu.org/Features/Rust/QOM. I got to the point where at
least this compiles:

qdev_define_type!(c"test-device", TestDevice);
impl ObjectImpl for TestDevice {}
impl DeviceImpl for TestDevice {}

fn main() {
let d = TestDevice::new();
d.cold_reset();
}

Of course the code makes no sense but it's a start.

One thing that would be very useful is to have an Error
implementation. Looking at what Marc-André did for Error*
(https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/20210907121943.3498701-13-marcandre.lur...@redhat.com/),
his precise implementation relies on his code to go back and forth
between Rust representation, borrowed C object with Rust bindings and
owned C object with Rust bindings. But I think we can at least have
something like this:

// qemu::Error
pub struct Error {
msg: String,
/// Appends the print string of the error to the msg if not None
cause: Option>,
location: Option<(String, u32)>
}

impl std::error::Error for Error { ... }

impl Error {
  ...
  fn into_c_error(self) -> *const bindings::Error { ... }
}

// qemu::Result
type Result = Result;

which can be implemented without too much code. This way any "bool
f(..., Error *)" function (example: realize :)) could be implemented
as returning qemu::Result<()>.

Paolo




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-14 Thread Manos Pitsidianakis

On Thu, 13 Jun 2024 23:57, Paolo Bonzini  wrote:

On Thu, Jun 13, 2024 at 11:16 AM Daniel P. Berrangé  wrote:

I guess there's a balance to be had somewhere on the spectrum between doing
everything against the raw C binding, vs everything against a perfectly
idiomatic Rust API wrapping the C bniding. The latter might be the ideal,
but from a pragmmatic POV I doubt we want the barrier to entry to be that
high.


Yes, I agree. I guess we could make things work step by step, even
committing something that only focuses on the build system like
Manos's work (I'll review it).

I can try to look at the basic QOM interface.

Manos, can you create a page on the wiki? Something like
https://wiki.qemu.org/Features/Meson.



Certainly! Just to make sure I understood correctly, you mean a wiki 
page describing how things work and tracking the progress?


I added https://wiki.qemu.org/Features/Meson/Rust

And a Meson category https://wiki.qemu.org/Category:Meson

Thanks,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Paolo Bonzini
On Thu, Jun 13, 2024 at 11:16 AM Daniel P. Berrangé  wrote:
> I guess there's a balance to be had somewhere on the spectrum between doing
> everything against the raw C binding, vs everything against a perfectly
> idiomatic Rust API wrapping the C bniding. The latter might be the ideal,
> but from a pragmmatic POV I doubt we want the barrier to entry to be that
> high.

Yes, I agree. I guess we could make things work step by step, even
committing something that only focuses on the build system like
Manos's work (I'll review it).

I can try to look at the basic QOM interface.

Manos, can you create a page on the wiki? Something like
https://wiki.qemu.org/Features/Meson.

Paolo

> Is this not something we can figure out organically as part of the code
> design and review processes ?
>
> e.g. if during review we see a device impl doing something where a higher
> level API would have unambiguous benefits, and creatino of such a higher
> level API is a practically achieveable task, then ask for it. If a higher
> level API is desirable, but possibly not practical, then raise it as an
> potential idea, but be willing to accept the technical debt.
>
> With regards,
> Daniel
> --
> |: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o-https://fstop138.berrange.com :|
> |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|
>




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Paolo Bonzini
On Thu, Jun 13, 2024 at 6:06 PM Zhao Liu  wrote:
> I think deeper and higher level bindings will have more opens and will
> likely require more discussion and exploration. So could we explore this
> direction on another reference Rust device?
>
> I also think there won’t be too many Rust devices in the short term.
> Going back to tweak or enhance existing Rust devices may not require too
> much effort, once we have a definitive answer.
>
> I wonder if x86 could also implement a rust device (like the x86 timer
> you mentioned before, hw/i386/kvm/i8254.c or hw/timer/i8254.c IIRC) to
> try this? Or would you recommend another x86 device? :-)

A timer device is a good idea, just because it's another pretty stable
low-level QEMU API.

The problem with hw/timer/i8254.c is that it has the KVM version, as
you found. The HPET is an alternative though.


Paolo




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Zhao Liu
Hi Paolo,

On Thu, Jun 13, 2024 at 09:56:39AM +0200, Paolo Bonzini wrote:
> Date: Thu, 13 Jun 2024 09:56:39 +0200
> From: Paolo Bonzini 
> Subject: Re: [RFC PATCH v2 3/5] rust: add PL011 device model
> 
> Il gio 13 giu 2024, 09:13 Daniel P. Berrangé  ha
> scritto:
> 
> > On Wed, Jun 12, 2024 at 11:27:04PM +0200, Paolo Bonzini wrote:
> > > Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
> > > manos.pitsidiana...@linaro.org> ha scritto:
> > >
> > > > In any case, it is out of scope for this RFC. Introducing wrappers
> > would
> > > > be a gradual process.
> > > >
> > >
> > > Sure, how would you feel about such bindings being developed on list, and
> > > maintained in a (somewhat) long-lived experimental branch?
> >
> > IMHO any higher level binding APIs for Rust should be acceptable in the
> > main QEMU tree as soon as we accept Rust functionality. They can evolve
> > in-tree based on the needs of whomever is creating and/or consuming them.
> >
> 
> My question is the opposite, should we accept Rust functionality without
> proper high level bindings? I am afraid that, if more Rust devices are
> contributed, it becomes technical debt to have a mix of idiomatic and C-ish
> code. If the answer is no, then this PL011 device has to be developed out
> of tree.

I think deeper and higher level bindings will have more opens and will
likely require more discussion and exploration. So could we explore this
direction on another reference Rust device?

I also think there won’t be too many Rust devices in the short term.
Going back to tweak or enhance existing Rust devices may not require too
much effort, once we have a definitive answer.

I wonder if x86 could also implement a rust device (like the x86 timer
you mentioned before, hw/i386/kvm/i8254.c or hw/timer/i8254.c IIRC) to
try this? Or would you recommend another x86 device? :-)

I'd be willing to help Manos try it if you think it's fine.

Regards,
Zhao




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Daniel P . Berrangé
On Thu, Jun 13, 2024 at 11:59:12AM +0300, Manos Pitsidianakis wrote:
> On Thu, 13 Jun 2024 11:53, "Daniel P. Berrangé"  wrote:
> > On Thu, Jun 13, 2024 at 11:41:38AM +0300, Manos Pitsidianakis wrote:
> > > > > diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> > > > > new file mode 100644
> > > > > index 00..ebecb99fe0
> > > > > --- /dev/null
> > > > > +++ b/rust/rustfmt.toml
> > > > > @@ -0,0 +1,7 @@
> > > > > +edition = "2021"
> > > > > +format_generated_files = false
> > > > > +format_code_in_doc_comments = true
> > > > > +format_strings = true
> > > > > +imports_granularity = "Crate"
> > > > > +group_imports = "StdExternalCrate"
> > > > > +wrap_comments = true
> > > > > > > About the Rust style, inspired from the discussion on my
> > > previous
> > > > simpletrace-rust [1], it looks like people prefer the default rust style
> > > > and use the default check without custom configurations.
> > > > > More style requirements are also an open, especially for
> > > unstable ones,
> > > > and it would be better to split this part into a separate patch, so that
> > > > the discussion about style doesn't overshadow the focus on your example.
> > > > > [1]:
> > > https://lore.kernel.org/qemu-devel/zlnbgwk29ds9f...@redhat.com/
> > > >
> > > 
> > > I had read that discussion and had that in mind. There's no need to worry
> > > about format inconsistencies; these options are unstable  -nightly only-
> > > format options and they don't affect the default rust style (they actually
> > > follow it). If you run a stable cargo fmt you will see the code won't 
> > > change
> > > (but might complain that these settings are nightly only).
> > > 
> > > What they do is extra work on top of the default style. If anything ends 
> > > up
> > > incompatible with stable I agree it must be removed, there's no sense in
> > > having a custom Rust style when the defaults are so reasonable.
> > 
> > This doesn't make sense. One the one hand you're saying the rules don't
> > have any effect on the code style vs the default, but on the otherhand
> > saying they do "extra work" on top of the default style. Those can't
> > both be true.
> 
> No, I fear there's a confusion here. It means that if you run the stable
> rustfmt with the default options the code doesn't change. I.e. it does not
> conflict with the default style.
> 
> What it does is group imports, format text in doc comments (which stable
> rustfmt doesn't touch at all) and also splits long strings into several
> lines, which are all helpful for e-mail patch reviews.

Ah ok.  Are we expecting these options to become part of stable rustfmt ?

I would expect our contributors to primarily be using the Rust toolchain
that comes with their distro, and not unstable -nightly toolchain. So I
still wonder if this rustfmt config will have much real world benefit ?


With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Daniel P . Berrangé
On Thu, Jun 13, 2024 at 09:56:39AM +0200, Paolo Bonzini wrote:
> Il gio 13 giu 2024, 09:13 Daniel P. Berrangé  ha
> scritto:
> 
> > On Wed, Jun 12, 2024 at 11:27:04PM +0200, Paolo Bonzini wrote:
> > > Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
> > > manos.pitsidiana...@linaro.org> ha scritto:
> > >
> > > > In any case, it is out of scope for this RFC. Introducing wrappers
> > would
> > > > be a gradual process.
> > > >
> > >
> > > Sure, how would you feel about such bindings being developed on list, and
> > > maintained in a (somewhat) long-lived experimental branch?
> >
> > IMHO any higher level binding APIs for Rust should be acceptable in the
> > main QEMU tree as soon as we accept Rust functionality. They can evolve
> > in-tree based on the needs of whomever is creating and/or consuming them.
> >
> 
> My question is the opposite, should we accept Rust functionality without
> proper high level bindings? I am afraid that, if more Rust devices are
> contributed, it becomes technical debt to have a mix of idiomatic and C-ish
> code. If the answer is no, then this PL011 device has to be developed out
> of tree.

I guess there's a balance to be had somewhere on the spectrum between doing
everything against the raw C binding, vs everything against a perfectly
idiomatic Rust API wrapping the C bniding. The latter might be the ideal,
but from a pragmmatic POV I doubt we want the barrier to entry to be that
high.

Is this not something we can figure out organically as part of the code
design and review processes ?

e.g. if during review we see a device impl doing something where a higher
level API would have unambiguous benefits, and creatino of such a higher
level API is a practically achieveable task, then ask for it. If a higher
level API is desirable, but possibly not practical, then raise it as an
potential idea, but be willing to accept the technical debt.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Manos Pitsidianakis

On Thu, 13 Jun 2024 11:53, "Daniel P. Berrangé"  wrote:

On Thu, Jun 13, 2024 at 11:41:38AM +0300, Manos Pitsidianakis wrote:

> > diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> > new file mode 100644
> > index 00..ebecb99fe0
> > --- /dev/null
> > +++ b/rust/rustfmt.toml
> > @@ -0,0 +1,7 @@
> > +edition = "2021"
> > +format_generated_files = false
> > +format_code_in_doc_comments = true
> > +format_strings = true
> > +imports_granularity = "Crate"
> > +group_imports = "StdExternalCrate"
> > +wrap_comments = true
> > 
> 
> About the Rust style, inspired from the discussion on my previous

> simpletrace-rust [1], it looks like people prefer the default rust style
> and use the default check without custom configurations.
> 
> More style requirements are also an open, especially for unstable ones,

> and it would be better to split this part into a separate patch, so that
> the discussion about style doesn't overshadow the focus on your example.
> 
> [1]: https://lore.kernel.org/qemu-devel/zlnbgwk29ds9f...@redhat.com/
> 


I had read that discussion and had that in mind. There's no need to worry
about format inconsistencies; these options are unstable  -nightly only-
format options and they don't affect the default rust style (they actually
follow it). If you run a stable cargo fmt you will see the code won't change
(but might complain that these settings are nightly only).

What they do is extra work on top of the default style. If anything ends up
incompatible with stable I agree it must be removed, there's no sense in
having a custom Rust style when the defaults are so reasonable.


This doesn't make sense. One the one hand you're saying the rules don't
have any effect on the code style vs the default, but on the otherhand
saying they do "extra work" on top of the default style. Those can't
both be true.


No, I fear there's a confusion here. It means that if you run the stable 
rustfmt with the default options the code doesn't change. I.e. it does 
not conflict with the default style.


What it does is group imports, format text in doc comments (which stable 
rustfmt doesn't touch at all) and also splits long strings into several 
lines, which are all helpful for e-mail patch reviews.


Thanks,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Manos Pitsidianakis

On Thu, 13 Jun 2024 10:56, Paolo Bonzini  wrote:

Il gio 13 giu 2024, 09:13 Daniel P. Berrangé  ha
scritto:


On Wed, Jun 12, 2024 at 11:27:04PM +0200, Paolo Bonzini wrote:
> Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
> manos.pitsidiana...@linaro.org> ha scritto:
>
> > In any case, it is out of scope for this RFC. Introducing wrappers
would
> > be a gradual process.
> >
>
> Sure, how would you feel about such bindings being developed on list, and
> maintained in a (somewhat) long-lived experimental branch?

IMHO any higher level binding APIs for Rust should be acceptable in the
main QEMU tree as soon as we accept Rust functionality. They can evolve
in-tree based on the needs of whomever is creating and/or consuming them.



My question is the opposite, should we accept Rust functionality without
proper high level bindings? I am afraid that, if more Rust devices are
contributed, it becomes technical debt to have a mix of idiomatic and C-ish
code. If the answer is no, then this PL011 device has to be developed out
of tree.

Paolo


Getting Rust into QEMU, at least for our team at Linaro, is a long term 
commitment, so we will be responsible for preventing and fixing 
technical debt.  And it will be up to the hypothetical rust maintainers 
as well to "keep the garden tidy" so to speak.


To put it another way, I personally plan on making sure any bindings and 
any QEMU-ffi idioms that arise are all homogeneous and don't end up 
being a burden for the code base.


Your concern is valid, and thank you for raising it. I feel it is 
important to figure out how this will be managed, since it's also an 
argument for the final say in whether any of this code ends up in the 
upstream tree.


Thanks Paolo,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Daniel P . Berrangé
On Thu, Jun 13, 2024 at 11:41:38AM +0300, Manos Pitsidianakis wrote:
> > > diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> > > new file mode 100644
> > > index 00..ebecb99fe0
> > > --- /dev/null
> > > +++ b/rust/rustfmt.toml
> > > @@ -0,0 +1,7 @@
> > > +edition = "2021"
> > > +format_generated_files = false
> > > +format_code_in_doc_comments = true
> > > +format_strings = true
> > > +imports_granularity = "Crate"
> > > +group_imports = "StdExternalCrate"
> > > +wrap_comments = true
> > > 
> > 
> > About the Rust style, inspired from the discussion on my previous
> > simpletrace-rust [1], it looks like people prefer the default rust style
> > and use the default check without custom configurations.
> > 
> > More style requirements are also an open, especially for unstable ones,
> > and it would be better to split this part into a separate patch, so that
> > the discussion about style doesn't overshadow the focus on your example.
> > 
> > [1]: https://lore.kernel.org/qemu-devel/zlnbgwk29ds9f...@redhat.com/
> > 
> 
> I had read that discussion and had that in mind. There's no need to worry
> about format inconsistencies; these options are unstable  -nightly only-
> format options and they don't affect the default rust style (they actually
> follow it). If you run a stable cargo fmt you will see the code won't change
> (but might complain that these settings are nightly only).
> 
> What they do is extra work on top of the default style. If anything ends up
> incompatible with stable I agree it must be removed, there's no sense in
> having a custom Rust style when the defaults are so reasonable.

This doesn't make sense. One the one hand you're saying the rules don't
have any effect on the code style vs the default, but on the otherhand
saying they do "extra work" on top of the default style. Those can't
both be true.

> To sum it up, the style is essentially the default one, so there's no
> problem here!

If the style config is essentially the default one, then just remove
this config and make it actually the default.

Having this file exist sets the (incorrect) expectation that we would
be willing to accept changes that diverge from the default rust style,
and that's not desirable IMHO.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Manos Pitsidianakis

Hello Zhao :)

On Thu, 13 Jun 2024 11:30, Zhao Liu  wrote:

On Tue, Jun 11, 2024 at 01:33:32PM +0300, Manos Pitsidianakis wrote:

Date: Tue, 11 Jun 2024 13:33:32 +0300
From: Manos Pitsidianakis 
Subject: [RFC PATCH v2 3/5] rust: add PL011 device model
X-Mailer: git-send-email 2.44.0

This commit adds a re-implementation of hw/char/pl011.c in Rust.

It uses generated Rust bindings (produced by `ninja
aarch64-softmmu-generated.rs`) to
register itself as a QOM type/class.

How to build:

1. Make sure rust, cargo and bindgen (cargo install bindgen-cli) are
   installed
2. Configure a QEMU build with:
   --enable-system --target-list=aarch64-softmmu --enable-with-rust
3. Launching a VM with qemu-system-aarch64 should use the Rust version
   of the pl011 device (unless it is not set up so in hw/arm/virt.c; the
   type of the UART device is hardcoded).

   To confirm, inspect `info qom-tree` in the monitor and look for an
   `x-pl011-rust` device.

Signed-off-by: Manos Pitsidianakis 
---


Hi Manos,

Thanks for your example!


diff --git a/rust/pl011/Cargo.toml b/rust/pl011/Cargo.toml
new file mode 100644
index 00..db74f2b59f
--- /dev/null
+++ b/rust/pl011/Cargo.toml
@@ -0,0 +1,66 @@


...


+[lints]
+[lints.rustdoc]
+broken_intra_doc_links = "deny"
+redundant_explicit_links = "deny"
+[lints.clippy]
+# lint groups
+correctness = { level = "deny", priority = -1 }
+suspicious = { level = "deny", priority = -1 }
+complexity = { level = "deny", priority = -1 }
+perf = { level = "deny", priority = -1 }
+cargo = { level = "deny", priority = -1 }
+nursery = { level = "deny", priority = -1 }
+style = { level = "deny", priority = -1 }
+# restriction group
+dbg_macro = "deny"
+rc_buffer = "deny"
+as_underscore = "deny"
+assertions_on_result_states = "deny"
+# pedantic group
+doc_markdown = "deny"
+expect_fun_call = "deny"
+borrow_as_ptr = "deny"
+case_sensitive_file_extension_comparisons = "deny"
+cast_lossless = "deny"
+cast_ptr_alignment = "allow"
+large_futures = "deny"
+waker_clone_wake = "deny"
+unused_enumerate_index = "deny"
+unnecessary_fallible_conversions = "deny"
+struct_field_names = "deny"
+manual_hash_one = "deny"
+into_iter_without_iter = "deny"
+option_if_let_else = "deny"
+missing_const_for_fn = "deny"
+significant_drop_tightening = "deny"
+multiple_crate_versions = "deny"
+significant_drop_in_scrutinee = "deny"
+cognitive_complexity = "deny"
+missing_safety_doc = "allow"


...


diff --git a/rust/pl011/rustfmt.toml b/rust/pl011/rustfmt.toml
new file mode 12
index 00..39f97b043b
--- /dev/null
+++ b/rust/pl011/rustfmt.toml
@@ -0,0 +1 @@
+../rustfmt.toml


...


diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
new file mode 100644
index 00..ebecb99fe0
--- /dev/null
+++ b/rust/rustfmt.toml
@@ -0,0 +1,7 @@
+edition = "2021"
+format_generated_files = false
+format_code_in_doc_comments = true
+format_strings = true
+imports_granularity = "Crate"
+group_imports = "StdExternalCrate"
+wrap_comments = true



About the Rust style, inspired from the discussion on my previous
simpletrace-rust [1], it looks like people prefer the default rust style
and use the default check without custom configurations.

More style requirements are also an open, especially for unstable ones,
and it would be better to split this part into a separate patch, so that
the discussion about style doesn't overshadow the focus on your example.

[1]: https://lore.kernel.org/qemu-devel/zlnbgwk29ds9f...@redhat.com/



I had read that discussion and had that in mind. There's no need to 
worry about format inconsistencies; these options are unstable  -nightly 
only- format options and they don't affect the default rust style (they 
actually follow it). If you run a stable cargo fmt you will see the code 
won't change (but might complain that these settings are nightly only).


What they do is extra work on top of the default style. If anything ends 
up incompatible with stable I agree it must be removed, there's no sense 
in having a custom Rust style when the defaults are so reasonable.


To sum it up, the style is essentially the default one, so there's no 
problem here!


Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Zhao Liu
On Tue, Jun 11, 2024 at 01:33:32PM +0300, Manos Pitsidianakis wrote:
> Date: Tue, 11 Jun 2024 13:33:32 +0300
> From: Manos Pitsidianakis 
> Subject: [RFC PATCH v2 3/5] rust: add PL011 device model
> X-Mailer: git-send-email 2.44.0
> 
> This commit adds a re-implementation of hw/char/pl011.c in Rust.
> 
> It uses generated Rust bindings (produced by `ninja
> aarch64-softmmu-generated.rs`) to
> register itself as a QOM type/class.
> 
> How to build:
> 
> 1. Make sure rust, cargo and bindgen (cargo install bindgen-cli) are
>installed
> 2. Configure a QEMU build with:
>--enable-system --target-list=aarch64-softmmu --enable-with-rust
> 3. Launching a VM with qemu-system-aarch64 should use the Rust version
>of the pl011 device (unless it is not set up so in hw/arm/virt.c; the
>type of the UART device is hardcoded).
> 
>To confirm, inspect `info qom-tree` in the monitor and look for an
>`x-pl011-rust` device.
> 
> Signed-off-by: Manos Pitsidianakis 
> ---

Hi Manos,

Thanks for your example!

> diff --git a/rust/pl011/Cargo.toml b/rust/pl011/Cargo.toml
> new file mode 100644
> index 00..db74f2b59f
> --- /dev/null
> +++ b/rust/pl011/Cargo.toml
> @@ -0,0 +1,66 @@

...

> +[lints]
> +[lints.rustdoc]
> +broken_intra_doc_links = "deny"
> +redundant_explicit_links = "deny"
> +[lints.clippy]
> +# lint groups
> +correctness = { level = "deny", priority = -1 }
> +suspicious = { level = "deny", priority = -1 }
> +complexity = { level = "deny", priority = -1 }
> +perf = { level = "deny", priority = -1 }
> +cargo = { level = "deny", priority = -1 }
> +nursery = { level = "deny", priority = -1 }
> +style = { level = "deny", priority = -1 }
> +# restriction group
> +dbg_macro = "deny"
> +rc_buffer = "deny"
> +as_underscore = "deny"
> +assertions_on_result_states = "deny"
> +# pedantic group
> +doc_markdown = "deny"
> +expect_fun_call = "deny"
> +borrow_as_ptr = "deny"
> +case_sensitive_file_extension_comparisons = "deny"
> +cast_lossless = "deny"
> +cast_ptr_alignment = "allow"
> +large_futures = "deny"
> +waker_clone_wake = "deny"
> +unused_enumerate_index = "deny"
> +unnecessary_fallible_conversions = "deny"
> +struct_field_names = "deny"
> +manual_hash_one = "deny"
> +into_iter_without_iter = "deny"
> +option_if_let_else = "deny"
> +missing_const_for_fn = "deny"
> +significant_drop_tightening = "deny"
> +multiple_crate_versions = "deny"
> +significant_drop_in_scrutinee = "deny"
> +cognitive_complexity = "deny"
> +missing_safety_doc = "allow"

...

> diff --git a/rust/pl011/rustfmt.toml b/rust/pl011/rustfmt.toml
> new file mode 12
> index 00..39f97b043b
> --- /dev/null
> +++ b/rust/pl011/rustfmt.toml
> @@ -0,0 +1 @@
> +../rustfmt.toml

...

> diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
> new file mode 100644
> index 00..ebecb99fe0
> --- /dev/null
> +++ b/rust/rustfmt.toml
> @@ -0,0 +1,7 @@
> +edition = "2021"
> +format_generated_files = false
> +format_code_in_doc_comments = true
> +format_strings = true
> +imports_granularity = "Crate"
> +group_imports = "StdExternalCrate"
> +wrap_comments = true
> 

About the Rust style, inspired from the discussion on my previous
simpletrace-rust [1], it looks like people prefer the default rust style
and use the default check without custom configurations.

More style requirements are also an open, especially for unstable ones,
and it would be better to split this part into a separate patch, so that
the discussion about style doesn't overshadow the focus on your example.

[1]: https://lore.kernel.org/qemu-devel/zlnbgwk29ds9f...@redhat.com/

Regards,
Zhao





Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Paolo Bonzini
Il gio 13 giu 2024, 09:13 Daniel P. Berrangé  ha
scritto:

> On Wed, Jun 12, 2024 at 11:27:04PM +0200, Paolo Bonzini wrote:
> > Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
> > manos.pitsidiana...@linaro.org> ha scritto:
> >
> > > In any case, it is out of scope for this RFC. Introducing wrappers
> would
> > > be a gradual process.
> > >
> >
> > Sure, how would you feel about such bindings being developed on list, and
> > maintained in a (somewhat) long-lived experimental branch?
>
> IMHO any higher level binding APIs for Rust should be acceptable in the
> main QEMU tree as soon as we accept Rust functionality. They can evolve
> in-tree based on the needs of whomever is creating and/or consuming them.
>

My question is the opposite, should we accept Rust functionality without
proper high level bindings? I am afraid that, if more Rust devices are
contributed, it becomes technical debt to have a mix of idiomatic and C-ish
code. If the answer is no, then this PL011 device has to be developed out
of tree.

Paolo


>
> With regards,
> Daniel
> --
> |: https://berrange.com  -o-
> https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o-
> https://fstop138.berrange.com :|
> |: https://entangle-photo.org-o-
> https://www.instagram.com/dberrange :|
>
>


Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-13 Thread Daniel P . Berrangé
On Wed, Jun 12, 2024 at 11:27:04PM +0200, Paolo Bonzini wrote:
> Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
> manos.pitsidiana...@linaro.org> ha scritto:
> 
> > In any case, it is out of scope for this RFC. Introducing wrappers would
> > be a gradual process.
> >
> 
> Sure, how would you feel about such bindings being developed on list, and
> maintained in a (somewhat) long-lived experimental branch?

IMHO any higher level binding APIs for Rust should be acceptable in the
main QEMU tree as soon as we accept Rust functionality. They can evolve
in-tree based on the needs of whomever is creating and/or consuming them.


With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Manos Pitsidianakis

Good morning Paolo,

On Thu, 13 Jun 2024 00:27, Paolo Bonzini  wrote:
Il mer 12 giu 2024, 22:58 Manos Pitsidianakis < 
manos.pitsidiana...@linaro.org> ha scritto:


In any case, it is out of scope for this RFC. Introducing wrappers 
would be a gradual process.




Sure, how would you feel about such bindings being developed on list, 
and maintained in a (somewhat) long-lived experimental branch?


Hm the only thing that worries me is keeping it synced and postponing 
merge indefinitely. If we declare the rust parts as "experimental" we 
could evolve them quickly even on master.  What do the other maintainers 
think?


Thanks,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Paolo Bonzini
Il mer 12 giu 2024, 22:58 Manos Pitsidianakis <
manos.pitsidiana...@linaro.org> ha scritto:

> In any case, it is out of scope for this RFC. Introducing wrappers would
> be a gradual process.
>

Sure, how would you feel about such bindings being developed on list, and
maintained in a (somewhat) long-lived experimental branch?

Paolo


> Thanks,
> Manos
>
>


Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Manos Pitsidianakis

On Wed, 12 Jun 2024 19:06, "Daniel P. Berrangé"  wrote:

On Wed, Jun 12, 2024 at 05:14:56PM +0300, Manos Pitsidianakis wrote:

On Wed, 12 Jun 2024 15:29, Paolo Bonzini  wrote:
> I think this is extremely useful to show where we could go in the task
> of creating more idiomatic bindings.
> 
> On Tue, Jun 11, 2024 at 12:34 PM Manos Pitsidianakis

>  wrote:
> > +pub const PL011_ARM_INFO: TypeInfo = TypeInfo {
> > +name: TYPE_PL011.as_ptr(),
> > +parent: TYPE_SYS_BUS_DEVICE.as_ptr(),
> > +instance_size: core::mem::size_of::(),
> > +instance_align: core::mem::align_of::(),
> > +instance_init: Some(pl011_init),
> > +instance_post_init: None,
> > +instance_finalize: None,
> > +abstract_: false,
> > +class_size: 0,
> > +class_init: Some(pl011_class_init),
> > +class_base_init: None,
> > +class_data: core::ptr::null_mut(),
> > +interfaces: core::ptr::null_mut(),
> > +};
> 
> QOM is certainly a major part of what we need to do for idiomatic

> bindings. This series includes both using QOM objects (chardev) and
> defining them.
> 
> For using QOM objects, there is only one strategy that we need to

> implement for both Chardev and DeviceState/SysBusDevice which is nice.
> We can probably take inspiration from glib-rs, see for example
> - https://docs.rs/glib/latest/glib/object/trait.Cast.html
> - https://docs.rs/glib/latest/glib/object/trait.ObjectType.html
> - https://docs.rs/glib/latest/glib/object/struct.ObjectRef.html


There was consensus in the community call that we won't be writing Rust APIs
for internal C QEMU interfaces; or at least, that's not the goal


I think that is over-stating things. This was only mentioned in passing
and my feeling was that we didn't have that detailed of a discussion
because at this stage such a discussion is a bit like putting the cart
before the horse.

While the initial focus might be to just consume a Rust API that is a
1:1 mapping of the C API, I expect that over time we'll end up writing
various higher level Rust wrappers around the C API. If we didn't do that,
then in effect we'd be making ourselves write psuedo-C code in Rust,
undermining many of the benefits we could get.



In any case, it is out of scope for this RFC. Introducing wrappers would 
be a gradual process.


Thanks,
Manos



Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Daniel P . Berrangé
On Wed, Jun 12, 2024 at 05:14:56PM +0300, Manos Pitsidianakis wrote:
> On Wed, 12 Jun 2024 15:29, Paolo Bonzini  wrote:
> > I think this is extremely useful to show where we could go in the task
> > of creating more idiomatic bindings.
> > 
> > On Tue, Jun 11, 2024 at 12:34 PM Manos Pitsidianakis
> >  wrote:
> > > +pub const PL011_ARM_INFO: TypeInfo = TypeInfo {
> > > +name: TYPE_PL011.as_ptr(),
> > > +parent: TYPE_SYS_BUS_DEVICE.as_ptr(),
> > > +instance_size: core::mem::size_of::(),
> > > +instance_align: core::mem::align_of::(),
> > > +instance_init: Some(pl011_init),
> > > +instance_post_init: None,
> > > +instance_finalize: None,
> > > +abstract_: false,
> > > +class_size: 0,
> > > +class_init: Some(pl011_class_init),
> > > +class_base_init: None,
> > > +class_data: core::ptr::null_mut(),
> > > +interfaces: core::ptr::null_mut(),
> > > +};
> > 
> > QOM is certainly a major part of what we need to do for idiomatic
> > bindings. This series includes both using QOM objects (chardev) and
> > defining them.
> > 
> > For using QOM objects, there is only one strategy that we need to
> > implement for both Chardev and DeviceState/SysBusDevice which is nice.
> > We can probably take inspiration from glib-rs, see for example
> > - https://docs.rs/glib/latest/glib/object/trait.Cast.html
> > - https://docs.rs/glib/latest/glib/object/trait.ObjectType.html
> > - https://docs.rs/glib/latest/glib/object/struct.ObjectRef.html
> 
> 
> There was consensus in the community call that we won't be writing Rust APIs
> for internal C QEMU interfaces; or at least, that's not the goal

I think that is over-stating things. This was only mentioned in passing
and my feeling was that we didn't have that detailed of a discussion
because at this stage such a discussion is a bit like putting the cart
before the horse.

While the initial focus might be to just consume a Rust API that is a
1:1 mapping of the C API, I expect that over time we'll end up writing
various higher level Rust wrappers around the C API. If we didn't do that,
then in effect we'd be making ourselves write psuedo-C code in Rust,
undermining many of the benefits we could get.

With regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Paolo Bonzini
On Wed, Jun 12, 2024 at 4:42 PM Manos Pitsidianakis
 wrote:
> There was consensus in the community call that we won't be writing Rust
> APIs for internal C QEMU interfaces; or at least, that's not the goal

I disagree with that. We need _some_ kind of bindings, otherwise we
have too much unsafe code, and the benefit of Rust becomes so much
lower that I doubt the utility.

If something is used by only one device then fine, but when some kind
of unsafe code repeats across most if not all devices, that is a
problem. It can be macros, it can be smart pointers, that remains to
be seen---but repetition should be a warning signal that _something_
is necessary.

> >For definining new classes I think it's okay if Rust does not support
> >writing superclasses yet, only leaves.
> >
> >I would make a QOM class written in Rust a struct that only contains
> >the new fields. The struct must implement Default and possibly Drop
> >(for finalize).
>
> The object is allocated and freed from C, hence it is not Dropped. We're
> only ever accessing it from a reference retrieved from a QEMU provided
> raw pointer. If the struct gains heap object fields like Box or Vec or
> String, they'd have to be dropped manually on _unrealize.

That's my point, if you have

  struct MyDevice_Inner {
data: Vec,
  }

  struct MyDevice {
parent_obj: qemu::bindings::SysBusDevice,
private: ManuallyDrop,
  }

then the instance_finalize method can simply do

  pub instance_finalize(self: *c_void)
  {
let dev = self as *mut MyDevice;
unsafe { ManuallyDrop::drop(dev.private) }
  }

Don't do it on _unrealize, create macros that do it for you.

> >and then a macro defines a wrapper struct that includes just two
> >fields, one for the superclass and one for the Rust struct.
> >instance_init can initialize the latter with Default::default().
> >
> >  struct PL011 {
> >parent_obj: qemu::bindings::SysBusDevice,
> >private: PL011_Inner,
> >  }
>
> a nested struct is not necessary for using the Default trait

Agreed, but a nested struct is nice anyway in my opinion as a boundary
between the C-ish and Rust idiomatic code.

> >"private" probably should be RefCell, avoiding the unsafe
> >
> >state.as_mut().read(addr, size)
>
>
> RefCell etc are not FFI safe.

Why does it matter? Everything after the SysBusDevice is private.

> Also, nested fields must be visible so that the offset_of! macro works, for 
> QOM properties.

Note that QOM properties do not use offset_of; qdev properties do.
Using qdev properties is much easier because they hide visitors, but
again - not necessary, sometimes going lower-level can be easier if
the API you wrap is less C-ish.

Also, you can define constants (including properties) in contexts
where non-public fields are visible:

use std::mem;
pub struct Foo {
_x: i32,
y: i32,
}
impl Foo {
pub const OFFSET_Y: usize = mem::offset_of!(Foo, y);
}
fn main() {
println!("{}", Foo::OFFSET_Y);
}

Any offset needed to go past the SysBusDevice and any other fields
before MyDevice_Inner can be added via macros. Also note that it
doesn't _have_ to be RefCell; RefCell isn't particularly magic. We can
implement our own interior mutability thingy that is more friendly to
qdev properties, or that includes the ManuallyDrop<> thing from above,
or both.

For example you could have

  type PL011 = QOMImpl;

and all the magic (for example Borrow, the TypeInfo, the
instance_init and instance_finalize function) would be in QOMImpl.

My point is: let's not focus on having a C-like API. It's the easiest
thing to do but not the target.

> Finally,
>
>  state.as_mut().read(addr, size)
>
> Is safe since we receive a valid pointer from QEMU. This fact cannot be
> derived by the compiler, which is why it has an `unsafe` keyword. That
> does not mean that the use here is unsafe.

Yes, it is safe otherwise it would be undefined behavior, but there
are no checks of the kind that you have in Rust whenever you have
&mut.

state.as_mut() implies that no other references to state are in use;
but there are (you pass it as the opaque value to both the
MemoryRegionOps and the chardev frontend callbacks). This is why I
think something like RefCell is needed to go from a shared reference
to an exclusive one (interior mutability).

> >There should also be macros to define the wrappers for MMIO MemoryRegions.
>
> Do you mean the MemoryRegionOps?

Yes.

> I wanted to focus on the build system integration for the first RFC
> which is why there are some macros but not in every place it makes
> sense.

Yes, absolutely. We need to start somewhere.

Paolo




Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Manos Pitsidianakis

On Wed, 12 Jun 2024 15:29, Paolo Bonzini  wrote:

I think this is extremely useful to show where we could go in the task
of creating more idiomatic bindings.

On Tue, Jun 11, 2024 at 12:34 PM Manos Pitsidianakis
 wrote:

+fn main() {
+println!("cargo::rerun-if-env-changed=MESON_BUILD_DIR");
+println!("cargo::rerun-if-env-changed=MESON_BUILD_ROOT");
+println!("cargo::rerun-if-changed=src/generated.rs.inc");


Why do you need this rerun-if-changed?


To show an error from build.rs in case the file is deleted and the build 
is not via meson





+pub const PL011_ARM_INFO: TypeInfo = TypeInfo {
+name: TYPE_PL011.as_ptr(),
+parent: TYPE_SYS_BUS_DEVICE.as_ptr(),
+instance_size: core::mem::size_of::(),
+instance_align: core::mem::align_of::(),
+instance_init: Some(pl011_init),
+instance_post_init: None,
+instance_finalize: None,
+abstract_: false,
+class_size: 0,
+class_init: Some(pl011_class_init),
+class_base_init: None,
+class_data: core::ptr::null_mut(),
+interfaces: core::ptr::null_mut(),
+};


QOM is certainly a major part of what we need to do for idiomatic
bindings. This series includes both using QOM objects (chardev) and
defining them.

For using QOM objects, there is only one strategy that we need to
implement for both Chardev and DeviceState/SysBusDevice which is nice.
We can probably take inspiration from glib-rs, see for example
- https://docs.rs/glib/latest/glib/object/trait.Cast.html
- https://docs.rs/glib/latest/glib/object/trait.ObjectType.html
- https://docs.rs/glib/latest/glib/object/struct.ObjectRef.html



There was consensus in the community call that we won't be writing Rust 
APIs for internal C QEMU interfaces; or at least, that's not the goal


It's not necessary to make bindings to write idiomatic Rust. If you 
notice, most callbacks QEMU calls cast the pointer into the Rust struct 
which then calls its idiomatic type methods. I like abstraction a lot, 
but it has diminishing returns. We'll see how future Rust devices look 
like and we can then decide if extra code for abstractions is a good 
trade-off.




For definining new classes I think it's okay if Rust does not support
writing superclasses yet, only leaves.

I would make a QOM class written in Rust a struct that only contains
the new fields. The struct must implement Default and possibly Drop
(for finalize).


The object is allocated and freed from C, hence it is not Dropped. We're 
only ever accessing it from a reference retrieved from a QEMU provided 
raw pointer. If the struct gains heap object fields like Box or Vec or 
String, they'd have to be dropped manually on _unrealize.





 struct PL011_Inner {
   iomem: MemoryRegion,
   readbuff: u32.
   ...
 }

and then a macro defines a wrapper struct that includes just two
fields, one for the superclass and one for the Rust struct.
instance_init can initialize the latter with Default::default().

 struct PL011 {
   parent_obj: qemu::bindings::SysBusDevice,
   private: PL011_Inner,
 }


a nested struct is not necessary for using the Default trait. Consider a 
Default impl that sets parent_obj as a field memset to zero; on instance 
initialization we can do


 *self = Self {
   parent_obj: self.parent_obj,
   ..Self::default(),
 };


"private" probably should be RefCell, avoiding the unsafe

   state.as_mut().read(addr, size)



RefCell etc are not FFI safe. Also, nested fields must be visible so 
that the offset_of! macro works, for QOM properties. Finally, 


state.as_mut().read(addr, size)

Is safe since we receive a valid pointer from QEMU. This fact cannot be 
derived by the compiler, which is why it has an `unsafe` keyword. That 
does not mean that the use here is unsafe.




There should also be macros to define the wrappers for MMIO MemoryRegions.



Do you mean the MemoryRegionOps?





+pub fn realize(&mut self) {
+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::(),
+core::ptr::null_mut(),
+true,
+);
+}


Probably each set of callbacks (MemoryRegion, Chardev) needs to be a
struct that implements a trait.


+#[macro_export]
+macro_rules! define_property {
+($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = 
$defval:expr) => {
+$crate::generated::Property {
+name: $name,
+info: $prop,
+offset: ::core::mem::offset_of!($state, $field) as _,
+bitnr: 0,
+bitmask: 0,
+set_default: true,
+defval: $crate::generated::Property__bindgen_ty_1 { u: 
$defval.into() },
+arrayoffset: 0,
+arrayinfo: ::core::ptr::null(),
+arrayfieldsize: 0,
+link_type: ::core::ptr::null()

Re: [RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-12 Thread Paolo Bonzini
I think this is extremely useful to show where we could go in the task
of creating more idiomatic bindings.

On Tue, Jun 11, 2024 at 12:34 PM Manos Pitsidianakis
 wrote:
> +fn main() {
> +println!("cargo::rerun-if-env-changed=MESON_BUILD_DIR");
> +println!("cargo::rerun-if-env-changed=MESON_BUILD_ROOT");
> +println!("cargo::rerun-if-changed=src/generated.rs.inc");

Why do you need this rerun-if-changed?

> +pub const PL011_ARM_INFO: TypeInfo = TypeInfo {
> +name: TYPE_PL011.as_ptr(),
> +parent: TYPE_SYS_BUS_DEVICE.as_ptr(),
> +instance_size: core::mem::size_of::(),
> +instance_align: core::mem::align_of::(),
> +instance_init: Some(pl011_init),
> +instance_post_init: None,
> +instance_finalize: None,
> +abstract_: false,
> +class_size: 0,
> +class_init: Some(pl011_class_init),
> +class_base_init: None,
> +class_data: core::ptr::null_mut(),
> +interfaces: core::ptr::null_mut(),
> +};

QOM is certainly a major part of what we need to do for idiomatic
bindings. This series includes both using QOM objects (chardev) and
defining them.

For using QOM objects, there is only one strategy that we need to
implement for both Chardev and DeviceState/SysBusDevice which is nice.
We can probably take inspiration from glib-rs, see for example
- https://docs.rs/glib/latest/glib/object/trait.Cast.html
- https://docs.rs/glib/latest/glib/object/trait.ObjectType.html
- https://docs.rs/glib/latest/glib/object/struct.ObjectRef.html

For definining new classes I think it's okay if Rust does not support
writing superclasses yet, only leaves.

I would make a QOM class written in Rust a struct that only contains
the new fields. The struct must implement Default and possibly Drop
(for finalize).

  struct PL011_Inner {
iomem: MemoryRegion,
readbuff: u32.
...
  }

and then a macro defines a wrapper struct that includes just two
fields, one for the superclass and one for the Rust struct.
instance_init can initialize the latter with Default::default().

  struct PL011 {
parent_obj: qemu::bindings::SysBusDevice,
private: PL011_Inner,
  }

"private" probably should be RefCell, avoiding the unsafe

state.as_mut().read(addr, size)

There should also be macros to define the wrappers for MMIO MemoryRegions.

> +pub fn realize(&mut self) {
> +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::(),
> +core::ptr::null_mut(),
> +true,
> +);
> +}

Probably each set of callbacks (MemoryRegion, Chardev) needs to be a
struct that implements a trait.

> +#[macro_export]
> +macro_rules! define_property {
> +($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = 
> $defval:expr) => {
> +$crate::generated::Property {
> +name: $name,
> +info: $prop,
> +offset: ::core::mem::offset_of!($state, $field) as _,
> +bitnr: 0,
> +bitmask: 0,
> +set_default: true,
> +defval: $crate::generated::Property__bindgen_ty_1 { u: 
> $defval.into() },
> +arrayoffset: 0,
> +arrayinfo: ::core::ptr::null(),
> +arrayfieldsize: 0,
> +link_type: ::core::ptr::null(),
> +}
> +};

Perhaps we can define macros similar to the C DEFINE_PROP_*, and const
functions can be used to enforce some kind of type safety.

pub const fn check_type(_x: &T, y: T) -> T { y }

static VAR: i16 = 42i16;
static TEST: i8 = check_type(&VAR, 43i8);

pub fn main() { println!("{}", TEST); }

error[E0308]: mismatched types
 --> ff.rs:4:30
  |
4 | static TEST: i8 = check_type(&VAR, 43i8);
  |   --  expected `&i8`, found `&i16`
  |   |
  |   arguments to this function are incorrect
  |
  = note: expected reference `&i8`
 found reference `&i16`

Anyhow I think this is already very useful, because as the
abstractions are developed, it is possible to see how the device code
evolves.

Paolo




[RFC PATCH v2 3/5] rust: add PL011 device model

2024-06-11 Thread Manos Pitsidianakis
This commit adds a re-implementation of hw/char/pl011.c in Rust.

It uses generated Rust bindings (produced by `ninja
aarch64-softmmu-generated.rs`) to
register itself as a QOM type/class.

How to build:

1. Make sure rust, cargo and bindgen (cargo install bindgen-cli) are
   installed
2. Configure a QEMU build with:
   --enable-system --target-list=aarch64-softmmu --enable-with-rust
3. Launching a VM with qemu-system-aarch64 should use the Rust version
   of the pl011 device (unless it is not set up so in hw/arm/virt.c; the
   type of the UART device is hardcoded).

   To confirm, inspect `info qom-tree` in the monitor and look for an
   `x-pl011-rust` device.

Signed-off-by: Manos Pitsidianakis 
---
 MAINTAINERS|   6 +
 meson.build|   4 +
 rust/meson.build   |   2 +
 rust/pl011/.cargo/config.toml  |   2 +
 rust/pl011/.gitignore  |   2 +
 rust/pl011/Cargo.lock  | 120 +++
 rust/pl011/Cargo.toml  |  66 
 rust/pl011/README.md   |  42 +++
 rust/pl011/build.rs|  44 +++
 rust/pl011/deny.toml   |  57 
 rust/pl011/meson.build |   7 +
 rust/pl011/rustfmt.toml|   1 +
 rust/pl011/src/definitions.rs  |  95 ++
 rust/pl011/src/device.rs   | 531 ++
 rust/pl011/src/device_class.rs |  95 ++
 rust/pl011/src/generated.rs|   5 +
 rust/pl011/src/lib.rs  | 581 +
 rust/pl011/src/memory_ops.rs   |  38 +++
 rust/rustfmt.toml  |   7 +
 19 files changed, 1705 insertions(+)
 create mode 100644 rust/pl011/.cargo/config.toml
 create mode 100644 rust/pl011/.gitignore
 create mode 100644 rust/pl011/Cargo.lock
 create mode 100644 rust/pl011/Cargo.toml
 create mode 100644 rust/pl011/README.md
 create mode 100644 rust/pl011/build.rs
 create mode 100644 rust/pl011/deny.toml
 create mode 100644 rust/pl011/meson.build
 create mode 12 rust/pl011/rustfmt.toml
 create mode 100644 rust/pl011/src/definitions.rs
 create mode 100644 rust/pl011/src/device.rs
 create mode 100644 rust/pl011/src/device_class.rs
 create mode 100644 rust/pl011/src/generated.rs
 create mode 100644 rust/pl011/src/lib.rs
 create mode 100644 rust/pl011/src/memory_ops.rs
 create mode 100644 rust/rustfmt.toml

diff --git a/MAINTAINERS b/MAINTAINERS
index ff6117f41d..e77a3d4169 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1181,6 +1181,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 
+S: Maintained
+F: rust/pl011/
+
 AVR Machines
 -
 
@@ -4229,6 +4234,7 @@ S: Maintained
 F: scripts/cargo_wrapper.py
 F: rust/meson.build
 F: rust/wrapper.h
+F: rust/rustfmt.toml
 
 Miscellaneous
 -
diff --git a/meson.build b/meson.build
index a08c975ef9..23e8c43562 100644
--- a/meson.build
+++ b/meson.build
@@ -296,6 +296,10 @@ if get_option('with_rust').allowed()
 endif
 with_rust = cargo.found()
 
+if with_rust
+  subdir('rust')
+endif
+
 # default flags for all hosts
 # We use -fwrapv to tell the compiler that we require a C dialect where
 # left shift of signed integers is well defined and has the expected
diff --git a/rust/meson.build b/rust/meson.build
index e9660a3045..264787198f 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -67,6 +67,8 @@ endif
 
 rust_hw_target_list = {}
 
+subdir('pl011')
+
 foreach rust_hw_target, rust_hws: rust_hw_target_list
   foreach rust_hw_dev: rust_hws
 output = meson.current_build_dir() / rust_target_triple / rs_build_type / 
rust_hw_dev['output']
diff --git a/rust/pl011/.cargo/config.toml b/rust/pl011/.cargo/config.toml
new file mode 100644
index 00..241210ffa7
--- /dev/null
+++ b/rust/pl011/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+rustflags = ["-Crelocation-model=pic", "-Ctarget-feature=+crt-static"]
diff --git a/rust/pl011/.gitignore b/rust/pl011/.gitignore
new file mode 100644
index 00..28a02c847f
--- /dev/null
+++ b/rust/pl011/.gitignore
@@ -0,0 +1,2 @@
+target
+src/generated.rs.inc
diff --git a/rust/pl011/Cargo.lock b/rust/pl011/Cargo.lock
new file mode 100644
index 00..d0fa46f9f5
--- /dev/null
+++ b/rust/pl011/Cargo.lock
@@ -0,0 +1,120 @@
+# 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 = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcd