Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add devicetree support to Rust on Zephyr #76074

Closed
wants to merge 75 commits into from

Conversation

d3zd3z
Copy link
Collaborator

@d3zd3z d3zd3z commented Jul 18, 2024

This is the beginnings of adding support for the devicetree to Rust on Zephyr. This currently:

  • Decodes the generated zephyr.dts and the devicetree_generated.h header, and builds a representation of that DT in memory at build time.
  • Outputs the DT as a series of Rust modules. Currently support is fairly minimal, but a few things work:
    • The entire node tree is represented as a tree of modules.
    • Direct phandle references result in new modules that "pub use" the contents of their target. This effectively means, for example, Rust code can reference zephyr::devicetree::aliases::led0 and get the same node as the actual led node this alias points to. Deeper nested phandles are not yet resolved.
    • Values that are simple single numbers are output as u32 constants.
    • Everything else is output as a string constant, with _DEBUG appended to the symbol name, and the string a debug dump of the value data structure of that property.

Also, this is built on top of #75904.

d3zd3z added 19 commits July 15, 2024 12:35
Add the `CONFIG_RUST` Kconfig.  This can be set to indicate that an
application wishes to use Rust support.

Signed-off-by: David Brown <david.brown@linaro.org>
Until further variants are needed, this provides a `main()` function
that simply calls into the `rust_main()` function.  This is adequate for
applications where main can be directly written in Rust.

Signed-off-by: David Brown <david.brown@linaro.org>
The initial support crate for zephyr use within a Rust application.
This crate does two simple things:

- Processes the .config file generated for this build, and ensures that
  CONFIG_RUST is enabled.
- Provide a hanging Rust panic handler.

Signed-off-by: David Brown <david.brown@linaro.org>
This provides the function `rust_cargo_application()` within Cmake to
give applications written in Rust a simple way to start.

This implements the basic functionality needed to build a rust
application on Arm, including target mapping, and invoking cargo during
the build.

Signed-off-by: David Brown <david.brown@linaro.org>
This implements a simple hello world application in Rust.  Since there
are no bindings yet, this just directly calls `printk` from Rust code.

Signed-off-by: David Brown <david.brown@linaro.org>
Indicate the new code is maintained.

Signed-off-by: David Brown <david.brown@linaro.org>
Create a crate `zephyr-build` that contains the code that will run at
build time.  Move the bool kconfig handing from this.  This will make it
easier for an application crate that needs access to config entries to
do access them by:

- Adding a dependency to zephyr-build to `[build-dependencies]` in their
  Cargo.toml.
- Creating a build.rs, or adding a call to:
  zephyr_build::export_bool_kconfig() in it.

Signed-off-by: David Brown <david.brown@linaro.org>
As part of the build of the `zephyr` crate, convert string and numeric
entries from the .config file of the current build into constants.  This
mimics how these are available as defines in C code.

The defines are available under `zephyr::kconfig::CONFIG_...`.

Signed-off-by: David Brown <david.brown@linaro.org>
This is a bit awkward, as we don't have a clean interface between Rust
and the Zephyr C code, but copy and null-terminate the current board,
and include that in the printed message.

This demonstrates that the kconfig module generation is working.

Signed-off-by: David Brown <david.brown@linaro.org>
Add initial docs for Rust language support.  Explains the support
currently present, how to install the toolchain needed, and explains
what is in the current sample.

Signed-off-by: David Brown <david.brown@linaro.org>
The documentation system requires all of the samples to have unique
names, no matter what directory they are in.  Rename our sample to
`hello_rust` to avoid a conflict with the existing `hello_world` sample.

Signed-off-by: David Brown <david.brown@linaro.org>
Code-blocks for shell commands are of type 'shell', to avoid this
warning.

Signed-off-by: David Brown <david.brown@linaro.org>
Distinguish between 'int' and 'hex' Kconfig values.  Use `usize` for the
hex values, as these are unsigned and may have the high bit set.  But,
for 'int' values, use `isize`, and allow the constants to be negative.

Signed-off-by: David Brown <david.brown@linaro.org>
This is still very experimental, mark it in the Kconfig as such.

Signed-off-by: David Brown <david.brown@linaro.org>
For Arm targets, match the ABI selection defines from the
cmake/compiler/gcc/target_arm.cmake file.  What is important here is
that the floating point selection is the same between gcc and rustc.

Signed-off-by: David Brown <david.brown@linaro.org>
Because of a mismatched quote, shell quoting for this block fails
sphinx.  Removing the quite causes compliance to fail due to the
mispelling.  Fix this by just removing formatting entirely from the
block.

Signed-off-by: David Brown <david.brown@linaro.org>
Compliance fails if even an example refers to non-existent Kconfig
options.  Change these to real options, even though that is slightly
distracting.

Signed-off-by: David Brown <david.brown@linaro.org>
The Cortex-M4 should be the thumbv7em not thumbv7m.

Signed-off-by: David Brown <david.brown@linaro.org>
Make this a proper C prototype function that takes no arguments.

Signed-off-by: David Brown <david.brown@linaro.org>
@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Jul 26, 2024

I've rebased this on top of #76337, as having generated bindings makes a lot of this quite a bit easier.

Gcc automatically defines __SOFTFP__ on Cortex-M targets where soft
floating point is used.  Clang, which is used by bindgen, does not
define this.  Workaround this by detecting this situation, and defining
this.

Signed-off-by: David Brown <david.brown@linaro.org>
Implement a general critical section handler, using spinlocks, for Rust
users to be able to use the `critical-section` crate.  This crate is
used by other crates as well.

Signed-off-by: David Brown <david.brown@linaro.org>
Whether a device uses a gpio pin depends on the DT.  Allow this symbol
to be unused, for targets that doing have gpio pins defined.

Signed-off-by: David Brown <david.brown@linaro.org>
unsafe extern "C" fn blink(_p1: *mut c_void, _p2: *mut c_void, _p3: *mut c_void) {
warn!("Inside of blinky");

let mut led0 = zephyr::devicetree::aliases::led0::get_instance();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we somehow make use of Option types, similar to how DEVICE_DT_GET_OR_NULL would work? This would allow to re-use code for different platforms where runtime checks are forced if a device tree node would be available or not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems reasonable, but I'll have to think about how that would work. I do like the idea of the DT being actually present as modules, but I'm not aware of a way to query that, and it doesn't really make sense to query the existence of modules at compile time.

d3zd3z added 15 commits July 31, 2024 12:04
This crate runs bindgen at build time to generate bindings to the Zephyr
API surface.

Signed-off-by: David Brown <david.brown@linaro.org>
This adds an atomic to each static Rust-defined kobject to ensure that they
are properly initialized.  It adds a small amount of overhead to each
object, as well as to when they are first used.

Signed-off-by: David Brown <david.brown@linaro.org>
The bindgen tool will generate bindings for #defines that resolve to
numeric constants.  This misses some otherwise constant bindings that have
a type cast in them.

We can, however, export some of these, by making a const in the C code that
bindgen will export.

Signed-off-by: David Brown <david.brown@linaro.org>
Implement a simple static wrapper to use with Zephyr kernel objects, and
use this to implement static threads.  This defines a static thread and a
static thread stack that can be initialized with a simple rust function,
with no arguments.

Signed-off-by: David Brown <david.brown@linaro.org>
Start an implementation of the dining philosopher's problem, in Rust.
There is just a child thread, and the mutex use is unsafe.  But, this
demonstrates the new Rust thread support.

Signed-off-by: David Brown <david.brown@linaro.org>
When alloc is enabled for Rust code, provide an easier to use `spawn`
function that boxes a closure and sends it to the child side.  This
requires allocations to hold the data passed to the child.

Signed-off-by: David Brown <david.brown@linaro.org>
Change this to test the `spawn` function we have available with allocation.

Signed-off-by: David Brown <david.brown@linaro.org>
Mark this as a TODO, disabling putting the k_thread in the noinit section.
It is supposed to only do this when we aren't debugging initialization, but
the conditional attribute doesn't seem to work.  For now, put it in
initialized memory, which will run correctly, just a little longer on init
time, but the atomic will be initialized properly.

Signed-off-by: David Brown <david.brown@linaro.org>
`zephyr::sys::Mutex` is a simple wrapper for the k_mutex that provides safe
access to lock and unlock.

Signed-off-by: David Brown <david.brown@linaro.org>
This eliminates the unsafe operations here.

Signed-off-by: David Brown <david.brown@linaro.org>
This is a little complicated.  We currently just jump directly to rust's
panic, so we aren't likely to actually need these unwind tables.  But, they
would be needed if we ever reall paniced.  As of the time of this change,
the tables seem to just be 24 bytes of ROM space.

Signed-off-by: David Brown <david.brown@linaro.org>
This is a Mutex object, similar to that in Rust's std::sync::Mutex.  It
doesn't implement poisoning yet, as we have no poisoning to speak of.

This can be used as an `Arc<Mutex<T>>` to protect a block of data.

The initializer requires a sys::Mutex to be passed in, as these are
typically static in Rust applications.  The wrapped mutex can live in an
Arc.

Signed-off-by: David Brown <david.brown@linaro.org>
Make these symbols available to Rust code.  They are too complex for
bindgen to inline, so represent the values as consts, which does depend on
their specific values.

Signed-off-by: David Brown <david.brown@linaro.org>
The low-level mutex can be safely cloned (and is send as well).  Be sure to
derive clone so that it can be used this way.

Signed-off-by: David Brown <david.brown@linaro.org>
The philosopher demo now uses the "friendly" wrapped mutexes, and as part
of the demo, places an incrementing counter inside of the mutex.

Signed-off-by: David Brown <david.brown@linaro.org>
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Sep 30, 2024
@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 4, 2024

Rust on Zephyr work is happening on the zephyr-lang-rust module. This is no longer relevant.

@d3zd3z d3zd3z closed this Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants