[PATCH rtems-docs 1/1] user: Add docu for use of Rust with RTEMS

Frank Kühndel frank.kuehndel at embedded-brains.de
Fri Feb 23 16:09:39 UTC 2024


Hi Chris,

thanks for reviewing this patch.

On 2/21/24 03:42, Chris Johns wrote:
> Hi Frank
> 
> Thanks for this, it ia awesome.
> 
> On 17/2/2024 7:52 am, Frank Kuehndel wrote:
>> From: Frank Kühndel<frank.kuehndel at embedded-brains.de>
>>
>> ---
>>   user/index.rst           |   3 +-
>>   user/overview/index.rst  |   2 +
>>   user/rust/bare-metal.rst | 549 +++++++++++++++++++++++++++++++++++++++
>>   user/rust/index.rst      |  64 +++++
> Do you see Rust growing to size it needs a directory?

No. There will hopefully be an additional section on using Rust with 
libstd (in contrast to bare metal). Besides of that, I do not see any 
extension in the "not to far" future.

Just tell me where to put the files. I can also join all text in one 
file if desired.

>>   4 files changed, 617 insertions(+), 1 deletion(-)
>>   create mode 100644 user/rust/bare-metal.rst
>>   create mode 100644 user/rust/index.rst
>>
>> diff --git a/user/index.rst b/user/index.rst
>> index 5b7f3ce..0cc6b2c 100644
>> --- a/user/index.rst
>> +++ b/user/index.rst
>> @@ -18,7 +18,7 @@ RTEMS User Manual (|version|).
>>       ||copy|  2018 Shashvat Jain
>>       ||copy|  2018 Vidushi Vashishth
>>       ||copy|  2017 Tanu Hari Dixit
>> -    ||copy|  2016, 2019 embedded brains GmbH & Co. KG
>> +    ||copy|  2016, 2024 embedded brains GmbH & Co. KG
>>       ||copy|  2016, 2019 Sebastian Huber
>>       ||copy|  2012, 2022 Chris Johns
>>       ||copy|  2012, 2020 Gedare Bloom
>> @@ -51,5 +51,6 @@ RTEMS User Manual (|version|).
>>   
>>       tools/index
>>       rsb/index
>> +    rust/index
>>   
>>       glossary/index
>> diff --git a/user/overview/index.rst b/user/overview/index.rst
>> index 16389d9..cc292e1 100644
>> --- a/user/overview/index.rst
>> +++ b/user/overview/index.rst
>> @@ -66,6 +66,8 @@ RTEMS provides the following basic feature set:
>>   
>>       - Python and MicroPython
>>   
>> +    - :ref:`Rust <Rust>`
>> +
>>   - Parallel languages
>>   
>>       - :ref:term:`EMB²`
>> diff --git a/user/rust/bare-metal.rst b/user/rust/bare-metal.rst
>> new file mode 100644
>> index 0000000..b893f57
>> --- /dev/null
>> +++ b/user/rust/bare-metal.rst
>> @@ -0,0 +1,549 @@
>> +.. SPDX-License-Identifier: CC-BY-SA-4.0
>> +
>> +.. Copyright (C) 2024 embedded brains GmbH & Co. KG
>> +
>> +.. _RustBareMetal:
>> +
>> +Bare Metal Rust with RTEMS
>> +==========================
>> +
>> +To develop with Rust and RTEMS together, you must find a Rust bare metal
>> +target which matches an RTEMS BSP.
> What does a user look for in a BSP to meet this requirement?

The hardware must match. If you are sitting in front of board X with 
processor Y you must compile RTEMS for that board/processor and you must 
compile the Rust application for that board/processor.

I do not know any algorithm to find matches automatically if that was 
your question. It would be nice to generate a table with all possible 
matching combinations. One would need to read out all RTEMS BSP 
descriptions and all Rust targets and CPU features and say "yes, these 
two are for the same hardware".

>> The instructions in this section
>> +are for a SPARC and a Risc-V*hello world*  program. These examples use
>> +the combinations shown in the table below:
>> +
>> ++--------------------+------------------+----------------------------+--------------+
>> +| RTEMS Architecture | RTEMS BSP        | Rust Target                | Rust CPU     |
>> ++====================+==================+============================+==============+
>> +| rtems-sparc        | sparc/leon3      | sparc-unknown-none-elf     | leon3        |
>> ++--------------------+------------------+----------------------------+--------------+
>> +| rtems-riscv        | riscv/rv64imafdc | riscv64gc-unknown-none-elf | generic-rv64 |
>> ++--------------------+------------------+----------------------------+--------------+
>> +
>> +The following sources may be helpful to find a matching BSP and target:
>> +
>> +- ``./waf bsplist`` -- executed in an RTEMS git clone
>> +- ``source-builder/sb-set-builder --list-bsets`` -- executed in an
>> +  RTEMS source builder git clone
>> +- `RTEMS Supported Architectures<https://devel.rtems.org/wiki/TBR/UserManual/SupportedCPUs>`_
>> +- `RTEMS Board Support Packages<https://devel.rtems.org/wiki/TBR/Website/Board_Support_Packages>`_
>> +- ``rustc --print target-list``
>> +- ``rustc --target=riscv64gc-unknown-none-elf --print target-features``
>> +- ``rustc --target=riscv64gc-unknown-none-elf  --print target-cpus``
>> +- `Rust Platform Support<https://doc.rust-lang.org/nightly/rustc/platform-support.html>`_
>> +
>> +The sample instructions which follow build two executables using the
>> +same source code for the RTEMS configuration ``init.c`` and the Rust
>> +hello-world application ``lib.rs``. Only the configuration as well as
>> +the compile and link commands differ for SPARC Leon3 and RISC-V
>> +64 bit. The Rust application uses ``printk()`` from RTEMS to print
>> +text to the console.
>> +
>> +After building the RTEMS BSP and installing Rust, the basic steps are:
>> +
>> +(1) Compile the RTEMS configuration in ``init.c`` into an object
>> +    file using the GNU C compiler from the RTEMS tool chain.
>> +(2) Compile the Rust code containing ``main()`` into a
>> +    static library using the Rust compiler.
>> +(3) Link the static library with the Rust code,
>> +    the RTEMS configuration and the RTEMS OS libraries
>> +    together into one single executable.
>> +(4) Finally run the executable on a simulator.
>> +
>> +I build the examples in a container. This is optional. If you prefer
>> +to follow these instructions directly on your machine simply skip the
>> +section*Build a Container*. Just make sure that you machine meets all
>> +prerequisites to build the RTEMS tools and install the Rust tools.
>> +
>> +.. _RustBareMetal_Container:
>> +
>> +Build a Container
>> +-----------------
>> +
>> +The container must be able to execute the RTEMS source builder and to
>> +install and run the Rust tools. In an empty directory of your choice
>> +create the following ``Dockerfile``.
> Is a container required of could a script of a series of shell command also work?

The container is optional. It should make it more easy to end up with 
running hello-world examples without cluttering one's machine or 
fighting though missing package dependencies. Yet, one can do without 
any container provided one installs the needed pre-requisites on the 
computer used.

The commands in the Dockerfile are specific for Ubuntu 22.04 LTS. They 
will not work for other versions of Ubuntu or other distributions of 
GNU/Linux. If I put a script with these commands in the documentation 
then I fear some persons will try to execute it not matter what OS they 
have and face the consequences.

>> +
>> +.. code-block:: shell
>> +
>> +    cat >Dockerfile <<"EOF"
>> +    # Dockerfile to build a container image to use Rust on top of RTEMS
>> +    FROM ubuntu:22.04
>> +    RUN apt-get update && \
>> +        apt-get -y upgrade && \
>> +        apt-get install -y \
>> +            binutils \
>> +            bison \
>> +            bzip2 \
>> +            curl \
>> +            flex \
>> +            gcc \
>> +            g++ \
>> +            git \
>> +            gzip \
>> +            make \
>> +            patch \
>> +            pkg-config \
>> +            python3 \
>> +            python3-dev \
>> +            python-is-python3 \
>> +            qemu-system-misc \
>> +            texinfo \
>> +            unzip \
>> +            xz-utils && \
>> +        apt-get clean && \
>> +        rm -rf/var/lib/apt/lists/*
>> +    RUN useradd -c "Rust Developer" -g "users" \
>> +                -d "/home/ferris" --create-home "ferris" && \
>> +        mkdir -p /opt/rtems && \
>> +        chown ferris:users /opt/rtems && \
>> +        runuser -u ferris echo 'export PATH=/opt/rtems/6/bin:${PATH}' \
>> +                >>/home/ferris/.bashrc
>> +    USER ferris
>> +    WORKDIR /home/ferris
>> +    CMD ["/bin/bash"]
>> +    EOF
>> +
> How different to the normal dependency list needed to build RTEMS tools is this?

Syrroy, this is a mistake of mine. Find below an update which better 
matches the dependency list for Ubuntu in the user manual. Yet, this 
container is specific for this Rust example and cannot be exactly the 
"normal dependency list".

     cat >Dockerfile <<"EOF"
     # Dockerfile to build a container image to use Rust on top of RTEMS
     FROM ubuntu:22.04
     RUN apt-get update && \
             apt-get -y upgrade && \
             apt-get install -y \
             bison \
             build-essential \
             curl \
             flex \
             g++ \
             gdb \
             git \
             libncurses5-dev \
             ninja-build \
             pax \
             pkg-config \
             python3-dev \
             python-is-python3 \
             qemu-system-misc \
             texinfo \
             unzip \
             zlib1g-dev && \
         apt-get clean && \
         rm -rf /var/lib/apt/lists/*
     RUN useradd -c "Rust Developer" -g "users" \
                 -d "/home/ferris" --create-home "ferris" && \
         mkdir -p /opt/rtems && \
         chown ferris:users /opt/rtems && \
         runuser -u ferris echo 'export PATH=/opt/rtems/6/bin:${PATH}' \
                 >>/home/ferris/.bashrc
     USER ferris
     WORKDIR /home/ferris
     CMD ["/bin/bash"]
     EOF


> I am happy to see containers documented as an example of providing the needed
> dependences but only if the underlying dependences are listed as the packages
> listed are Ubuntu specific. Should using containers be a separate section under
> deployment? It is realy useful stuff you have provided here.

I am pro documenting container build files (maybe in chapter "Host 
Computer"?) but it is a complex topic. Containers may not have the same 
dependencies as (virtual) machines. Shall only Docker be supported or 
other container frameworks too? Is the container to be used rootful of 
rooless? A container for interactive develoment needs a volume which 
brings up the topic of getting the UID/GID right. What shall the 
container be used for? ... build only the tools? build RTEMS? build 
libbsd? build Rust? build other things? Furthermore, one must regularly 
check that the instructions in the documentation still work as security 
patches and esp. new releases of GNU/Linux distributions appear. We 
would need a simple and pragmatic approch ... and as always some time ...
> I hope you understand these lists rot over time and we end up fielding support
> question and then creating OS version lists or removing it.

Documentation erosion is an issure for all RTEMS documentation. I 
intentionally used `ubuntu:22.04` above and not `ubuntu:latest`.

For this Rust guide I believe it is enough to have one container. The 
"Hello World" example is only to get programmers started. They must 
adapt it to their needs, incl. the desired OS.

> Can python-is-python3 to removed and python virtual env be used? We need a
> single way to handle this problem with python in the project and virtual
> environments are portable.

python-is-python3 creates this link: /usr/bin/python -> python3. Without 
it /usr/bin/python does not exist. I have not tried but I think not 
having /usr/bin/python at all is a bit strange.

>> +I use Podman. If you prefer Docker simply replace ``podman``
>> +through ``docker`` in the shell commands below.
> Can we please avoid first person?

Ok. I will change all occurences.

>> +
>> +Build the container image ``rtems_rust``, create and start a container
>> +with these commands:
>> +
>> +.. code-block:: shell
>> +
>> +    podman build -t rtems_rust .
>> +    podman run -it --name=rusty_rtems rtems_rust bash
>> +
>> +To follow the step-by-step instructions of the next sub-sections,
>> +simply execute them as user ``ferris`` in the container. Note that
>> +this container will not automatically be deleted on ``exit``.
>> +The building of the RTEMS tools takes a while and you probably want
>> +to keep the container for further experiments.
>> +
>> +.. _RustBareMetal_RTEMSTools:
>> +
>> +Build the RTEMS Tools
>> +---------------------
>> +
>> +In an empty directory of your choice, clone the RTEMS source builder
>> +git repository:
>> +
>> +.. code-block:: shell
>> +
>> +    git clone git://git.rtems.org/rtems-source-builder.git rsb
>> +
>> +Next build the RTEMS tools. In this example, I need the tools for
>> +*SPARC*  and*RISC-V*  architectures. The source builder installs them
>> +in the prefix directory ``/opt/rtems/6``. The directory ``/opt/rtems``
>> +must exist and the user must have read and write access.
>> +
>> +.. code-block:: shell
>> +
>> +    cd rsb/rtems
>> +    ../source-builder/sb-set-builder --prefix /opt/rtems/6 \
>> +        6/rtems-sparc \
>> +        6/rtems-riscv
>> +    cd ../..
>> +
> Is this repeating what we have or should have else where? Could that be
> referenced? The container part is confusing my understanding of what is needed.

Yes, similar instructions appear in the "Quick Start" chapter. What do 
you prefer?

   * Adding a link to the relevant section and keep the
     instruction here or
   * remove the commands here and just write "install tools for
     6/rtems-sparc and 6/rtems-riscv" as described in
     [link to the relevant section].

>> +The tools will end up in ``/opt/rtems/6/bin`` and that directory
>> +should be part of the ``$PATH`` environment variable of the user. For
>> +example:
>> +
>> +.. code-block:: shell
>> +
>> +    export PATH=/opt/rtems/6/bin:${PATH}
>> +
>> +The following commands should work:
>> +
>> +.. code-block:: shell
>> +
>> +    sparc-rtems6-gcc --version
>> +    riscv-rtems6-gcc --version
>> +
>> +.. _RustBareMetal_RTEMSBSP:
>> +
>> +Build and Install the RTEMS BSPs
>> +--------------------------------
>> +
>> +Clone the RTEMS git repository:
>> +
>> +.. code-block:: shell
>> +
>> +    git clone git://git.rtems.org/rtems.git
>> +
>> +Create a ``config.ini`` file for the two BSPs for which your are going
>> +to build RTEMS:
>> +
>> +.. code-block:: shell
>> +
>> +    cd rtems
>> +
>> +    cat >config.ini <<"EOF"
>> +    [sparc/leon3]
>> +    RTEMS_SMP = True
>> +    [riscv/rv64imafdc]
>> +    EOF
>> +
>> +Build and install RTEMS:
>> +
>> +.. code-block:: shell
>> +
>> +    ./waf configure --prefix=/opt/rtems/6
>> +    ./waf
>> +    ./waf install
>> +
>> +Run some RTEMS tests to make sure the installation and the emulators
>> +are working:
>> +
>> +.. code-block:: shell
>> +
>> +    sparc-rtems6-sis -leon3 -nouartrx -r m 4 build/sparc/leon3/testsuites/samples/hello.exe
>> +    sparc-rtems6-sis -leon3 -nouartrx -r m 4 build/sparc/leon3/testsuites/samples/ticker.exe
>> +    qemu-system-riscv64 -M virt -nographic -bios build/riscv/rv64imafdc/testsuites/samples/hello.exe
>> +    qemu-system-riscv64 -M virt -nographic -bios build/riscv/rv64imafdc/testsuites/samples/ticker.exe
>> +
>> +Finally, leave the git working tree:
>> +
>> +.. code-block:: shell
>> +
>> +    cd ..
>> +
>> +.. _RustBareMetal_InstallRust:
>> +
>> +Install and Setup Rust Tools
>> +----------------------------
>> +
>> +Install Rust from the web-page with this command:
>> +
>> +.. code-block:: shell
>> +
>> +    curl --proto '=https' --tlsv1.2 -sSfhttps://sh.rustup.rs  | sh
>> +
>> +At this point you must setup the environment variables:
>> +
>> +.. code-block:: shell
>> +
>> +    source "$HOME/.cargo/env"
>> +
>> +Check that rust is correctly setup:
>> +
>> +.. code-block:: shell
>> +
>> +    rustup update
>> +    cargo --version
>> +
>> +.. _RustBareMetal_Sources:
>> +
>> +Setup a Rust Project and Create Sources
>> +---------------------------------------
>> +
>> +Write a simple RTEMS ``init.c`` to configure RTEMS in a new directory:
>> +
>> +.. code-block:: shell
>> +
>> +    mkdir example-rust
>> +    cd example-rust
>> +
>> +    cat >init.c <<"EOF"
>> +    /*
>> +     * Simple RTEMS configuration
>> +     */
>> +
>> +    #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
>> +    #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
>> +
>> +    #define CONFIGURE_UNLIMITED_OBJECTS
>> +    #define CONFIGURE_UNIFIED_WORK_AREAS
>> +
>> +    #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
>> +
>> +    #define CONFIGURE_INIT
>> +
>> +    #include <rtems/confdefs.h>
>> +    EOF
>> +
>> +Create a new Rust project which produces a static linked library:
>> +
>> +.. code-block:: shell
>> +
>> +    cargo new --lib --vcs=none hello-rtems
>> +    sed -i '/^#/ a \\n[lib]\ncrate-type = ["staticlib"]' hello-rtems/Cargo.toml
>> +
>> +Store the Rust application code:
>> +
>> +.. code-block:: rust
>> +
>> +    cat >hello-rtems/src/lib.rs <<"EOF"
>> +    #![no_std]
>> +    #![no_main]
>> +
>> +    use core::fmt::Write;
>> +    use core::ffi::c_char;
>> +
>> +    extern "C" {
>> +        fn printk(fmt: *const core::ffi::c_char, ...) -> core::ffi::c_int;
>> +        fn rtems_panic(fmt: *const core::ffi::c_char, ...) -> !;
>> +        fn rtems_shutdown_executive(fatal_code: u32);
>> +    }
>> +
>> +    /// Write text to the console using RTEMS `printk()` function
>> +    struct Console;
>> +
>> +    impl core::fmt::Write for Console {
>> +        fn write_str(&mut self, message: &str) -> core::fmt::Result {
>> +            const FORMAT_STR: &core::ffi::CStr = {
>> +                let Ok(s) = core::ffi::CStr::from_bytes_with_nul(b"%.*s\0") else {
>> +                    panic!()
>> +                };
>> +                s
>> +            };
>> +            if message.len() != 0 {
>> +                unsafe {
>> +                    printk(FORMAT_STR.as_ptr(), message.len() as core::ffi::c_int, message.as_ptr());
>> +                }
>> +            }
>> +            Ok(())
>> +        }
>> +    }
>> +
>> +    /// Our `Init()` calls `rust_main()` and handles errors
>> +    #[no_mangle]
>> +    pub extern "C" fn Init() {
>> +        if let Err(e) = rust_main() {
>> +            panic!("Main returned {:?}", e);
>> +        }
>> +        unsafe {
>> +            rtems_shutdown_executive( 0 );
>> +        }
>> +    }
>> +
>> +    /// This is the main function of this program
>> +    fn rust_main() -> Result<(), core::fmt::Error> {
>> +        let mut console = Console;
>> +        writeln!(console, "Hello from Rust")?;
>> +        Ok(())
>> +    }
>> +
>> +    /// Handle panic by forwarding it to the `rtems_panic()` handler
>> +    #[panic_handler]
>> +    fn panic(panic: &core::panic::PanicInfo) -> ! {
>> +        // The panic message can only be reached from libcore in unstable
>> +        // (i.e. nightly builds). Print at least the location raising the panic.
>> +        // Seehttps://www.ralfj.de/blog/2019/11/25/how-to-panic-in-rust.html
>> +        if let Some(location) = panic.location() {
>> +            const FORMAT_STR: *const c_char = {
>> +                const BYTES: &[u8] = b"Panic occurred at %.*s:%d:%d\n\0";
>> +                BYTES.as_ptr().cast()
>> +            };
>> +            if location.file().len() != 0 {
>> +                unsafe {
>> +                    rtems_panic(FORMAT_STR,
>> +                        location.file().len() as core::ffi::c_int,
>> +                        location.file().as_ptr(),
>> +                        location.line() as core::ffi::c_int,
>> +                        location.column() as core::ffi::c_int,
>> +                    );
>> +                }
>> +            }
>> +        }
>> +
>> +        // If there is no location, fall back to the basic.
>> +        let message = "Panic occured!";
>> +        const FORMAT_PTR: *const c_char = {
>> +            const BYTES: &[u8] = b"%.*s\n\0";
>> +            BYTES.as_ptr().cast()
>> +        };
>> +        unsafe {
>> +           rtems_panic(FORMAT_PTR,
>> +               message.len() as core::ffi::c_int,
>> +               message.as_ptr());
>> +        }
>> +    }
>> +    EOF
>> +
>> +Create a configuration file for Cargo:
>> +
>> +.. code-block:: shell
>> +
>> +    mkdir hello-rtems/.cargo
>> +
>> +    cat >hello-rtems/.cargo/config.toml <<"EOF"
>> +    [target.riscv64gc-unknown-none-elf]
>> +    # Either kind should work as a linker
>> +    linker = "riscv-rtems6-gcc"
>> +    # linker = "riscv-rtems6-clang"
>> +    rustflags = [
>> +        # See `rustc --target=riscv64gc-unknown-none-elf  --print target-cpus`
>> +        "-Ctarget-cpu=generic-rv64",
>> +        # The linker is a gcc compatible C Compiler
>> +        "-Clinker-flavor=gcc",
>> +        # Pass these options to the linker
>> +        "-Clink-arg=-march=rv64imafdc",
>> +        "-Clink-arg=-mabi=lp64d",
>> +        "-Clink-arg=-mcmodel=medany",
>> +        # Rust needs libatomic.a to satisfy Rust's compiler-builtin library
>> +        "-Clink-arg=-latomic",
>> +    ]
>> +    runner = "qemu-system-riscv64 -M virt -nographic -bios"
>> +
>> +    # Target available in rust nightly from 2023-07-18
>> +    [target.sparc-unknown-none-elf]
>> +    # Either kind should work as a linker
>> +    linker = "sparc-rtems6-gcc"
>> +    # linker = "sparc-rtems6-clang"
>> +    rustflags = [
>> +        # The target is LEON3
>> +        "-Ctarget-cpu=leon3",
>> +        # The linker is a gcc compatible C Compiler
>> +        "-Clinker-flavor=gcc",
>> +        # Pass these options to the linker
>> +        "-Clink-arg=-mcpu=leon3",
>> +        # Rust needs libatomic.a to satisfy Rust's compiler-builtin library
>> +        "-Clink-arg=-latomic",
>> +    ]
>> +    runner = "sparc-rtems6-sis -leon3 -nouartrx -r m 4"
>> +
>> +    [build]
>> +    target = ["riscv64gc-unknown-none-elf", "sparc-unknown-none-elf"]
>> +
>> +    [unstable]
>> +    build-std = ["core"]
>> +    EOF
>> +
>> +.. _RustBareMetal_BuildRiscV:
>> +
>> +Build and Run on RISC-V
>> +-----------------------
>> +
>> +First, download some additional files needed for this target:
>> +
>> +.. code-block:: shell
>> +
>> +    rustup target add riscv64gc-unknown-none-elf
>> +
>> +Compile the Rust source file into a static library:
>> +
>> +.. code-block:: shell
>> +
>> +    cd hello-rtems
>> +    cargo build --target=riscv64gc-unknown-none-elf
>> +    cd ..
>> +
>> +This should create
>> +``hello-rtems/target/riscv64gc-unknown-none-elf/debug/libhello_rtems.
>> +a``. Note that the project directory (``hello-rtems``) is written with
>> +a minus "``-``" while the library (``libhello_rtems.a``) is written
>> +with an underscore "``_``".
>> +
>> +Compile the RTEMS ``init.c`` file and link everything
>> +together into a single executable:
>> +
>> +.. code-block:: shell
>> +
>> +    export PKG_CONFIG_RISCV=/opt/rtems/6/lib/pkgconfig/riscv-rtems6-rv64imafdc.pc
>> +
>> +    riscv-rtems6-gcc -Wall -Wextra -O2 -g -fdata-sections -ffunction-sections \
>> +        $(pkg-config --cflags ${PKG_CONFIG_RISCV}) init.c -c -o init_riscv.o
>> +
>> +    riscv-rtems6-gcc init_riscv.o \
>> +      -Lhello-rtems/target/riscv64gc-unknown-none-elf/debug \
>> +      -lhello_rtems \
>> +      -ohello_rtems_riscv.exe \
>> +      $(pkg-config --variable=ABI_FLAGS ${PKG_CONFIG_RISCV}) \
>> +      $(pkg-config --libs ${PKG_CONFIG_RISCV})
>> +
>> +This should produce the executable file ``hello_rtems_riscv.exe``. Finally,
>> +run the executable on an emulator (``qemu``):
>> +
>> +.. code-block:: shell
>> +
>> +    rtems-run --rtems-bsp=rv64imafdc hello_rtems_riscv.exe
>> +
>> +The emulator run should produce the following output:
>> +
>> +.. code-block:: none
>> +
>> +    RTEMS Testing - Run, 6.0.not_released
>> +     Command Line: /opt/rtems/6/bin/rtems-run --rtems-bsp=rv64imafdc hello_rtems_riscv.exe
>> +     Host: Linux 7319d7ad96ee 5.14.21-150500.228.g3903735-default #1 SMP PREEMPT_DYNAMIC Fri Jan 19 17:58:02 UTC 2024 (3903735) x86_64
>> +     Python: 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
>> +    Host: Linux-5.14.21-150500.228.g3903735-default-x86_64-with-glibc2.35 (Linux 7319d7ad96ee 5.14.21-150500.228.g3903735-default #1 SMP PREEMPT_DYNAMIC Fri Jan 19 17:58:02 UTC 2024 (3903735) x86_64 x86_64)
>> +    Hello from Rust
>> +
>> +    [ RTEMS shutdown ]
>> +    RTEMS version: 6.0.0.b1fdf753387189afe720d3fa1ac13af5fb9943c2
>> +    RTEMS tools: 13.2.0 20230727 (RTEMS 6, RSB 43d029e85817bd78dc564ffa265c18fccc428dc4, Newlib 3cacedb)
>> +    executing thread ID: 0x0a010001
>> +    executing thread name: UI1
>> +    Run time     : 0:00:00.255214
>> +
>> +.. _RustBareMetal_BuildSparc:
>> +
>> +Build and Run on SPARC
>> +----------------------
>> +
>> +You need to use the Rust nightly build because the support for
>> +Gaisler LEON3/4/5 was added in July 2023 and is not yet available
>> +in stable Rust:
>> +
>> +.. code-block:: shell
>> +
>> +    rustup toolchain add nightly
>> +    rustup component add rust-src --toolchain=nightly
>> +
>> +Compile the Rust source file into a static library:
>> +
>> +.. code-block:: shell
>> +
>> +    cd hello-rtems
>> +    cargo +nightly build --target=sparc-unknown-none-elf
>> +    cd ..
>> +
>> +It should create
>> +``hello-rtems/target/sparc-unknown-none-elf/debug/libhello_rtems.a``.
>> +
>> +Compile the RTEMS ``init.c`` file and link everything
>> +together into an executable:
>> +
>> +.. code-block:: shell
>> +
>> +    export PKG_CONFIG_SPARC=/opt/rtems/6/lib/pkgconfig/sparc-rtems6-leon3.pc
>> +
>> +    sparc-rtems6-gcc -Wall -Wextra -O2 -g -fdata-sections -ffunction-sections \
>> +        $(pkg-config --cflags ${PKG_CONFIG_SPARC}) init.c -c -o init_sparc.o
>> +
>> +    sparc-rtems6-gcc init_sparc.o \
>> +        -qnolinkcmds -T linkcmds.leon3 \
>> +        -Lhello-rtems/target/sparc-unknown-none-elf/debug \
>> +        -lhello_rtems \
>> +        -ohello_rtems_sparc.exe \
>> +        $(pkg-config --libs ${PKG_CONFIG_SPARC})
>> +
>> +This should produce the executable file ``hello_rtems_sparc.exe``. Finally,
>> +run the executable on an emulator (``sis``):
>> +
>> +.. code-block:: shell
>> +
>> +    rtems-run --rtems-bsp=leon3-sis hello_rtems_sparc.exe
>> +
>> +The emulator run should produce the following output:
>> +
>> +.. code-block:: none
>> +
>> +    RTEMS Testing - Run, 6.0.not_released
>> +     Command Line: /opt/rtems/6/bin/rtems-run --rtems-bsp=leon3-sis hello_rtems_sparc.exe
>> +     Host: Linux 7319d7ad96ee 5.14.21-150500.228.g3903735-default #1 SMP PREEMPT_DYNAMIC Fri Jan 19 17:58:02 UTC 2024 (3903735) x86_64
>> +     Python: 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
>> +    Host: Linux-5.14.21-150500.228.g3903735-default-x86_64-with-glibc2.35 (Linux 7319d7ad96ee 5.14.21-150500.228.g3903735-default #1 SMP PREEMPT_DYNAMIC Fri Jan 19 17:58:02 UTC 2024 (3903735) x86_64 x86_64)
>> +
>> +     SIS - SPARC/RISCV instruction simulator 2.30,  copyright Jiri Gaisler 2020
>> +     Bug-reports tojiri at gaisler.se
>> +
>> +     LEON3 emulation enabled, 4 cpus online, delta 50 clocks
>> +
>> +     Loaded hello_rtems_sparc.exe, entry 0x40000000
>> +    Hello from Rust
>> +    cpu 0 in error mode (tt = 0x80)
>> +       218400  40019fa0:  91d02000   ta  0x0
>> +    Run time     : 0:00:00.255628
>> diff --git a/user/rust/index.rst b/user/rust/index.rst
>> new file mode 100644
>> index 0000000..f3d4a28
>> --- /dev/null
>> +++ b/user/rust/index.rst
>> @@ -0,0 +1,64 @@
>> +.. SPDX-License-Identifier: CC-BY-SA-4.0
>> +
>> +.. Copyright (C) 2024 embedded brains GmbH & Co. KG
>> +
>> +.. index:: Rust
>> +
>> +.. _Rust:
>> +
>> +Rust
>> +****
>> +
>> +The number of users of the modern programming language Rust grows
>> +steadily. Fans can opt for RTEMS as OS when writing Rust
>> +applications on embedded devices. The sections of this chapter
>> +provide step by step instructions to get started.
>> +
>> +There are two basic approaches to use Rust together with RTEMS:
>> +
>> +Bare metal Rust
>> +  The Rust compiler translates the application code for a target
>> +  without operating system -- for example ``sparc-unknown-none-elf``.
>> +  The disadvantage of this approach is that no standard Rust library
>> +  is available (``#![no_std]`` in Rust code). The advantage is
>> +  that all targets supported by both Rust and RTEMS can
>> +  immediately be used.
>> +
>> +Rust with std lib
>> +  The Rust compiler translates the application code for an RTEMS
>> +  specific target -- for example ``armv7-unknown-rtems-eabi``.
>> +  The advantage is that all functions from the standard Rust library
>> +  are available. The disadvantage is that such targets are rare.
>> +
>> +  At the time of writing no such target exists. A first target for ARM
>> +  is planed to be published soon. The reason for the lack of targets is
>> +  that one must be implemented for each architecture, published to the
>> +  Rust compiler sources and maintained by someone.
>> +
>> +Common to all approaches is the general way how Rust is used with RTEMS:
>> +
>> +(1) The RTEMS tools for the architecture are needed. See
>> +    :ref:`Install the Tool Suite <QuickStartTools>`.
> Is (2) sphinx RsT notation?

Good point. This is ReStructuredText notation but I will change all 
occurences to the "1." notation uses elsewhere in the documentation.

>> +
>> +(2) The RTEMS kernel for the BSP is compiled to libraries. See
>> +    :ref:`Build a Board Support Package (BSP) <QuickStartBSPBuild>`.
>> +
>> +(3) A Rust project for the application code is created and configured.
>> +
>> +(4) The Rust code of the application is compiled into a library
>> +    for the target.
>> +
>> +(5) The Rust application library and the RTEMS kernel libraries are
>> +    linked together into a single executable file.
>> +
>> +(6) The executable file is either run in an emulator or loaded onto
>> +    the hardware and executed there.
>> +
>> +At the time of writing, there is no common Rust interface for the
>> +pubic RTEMS functions available. Currently, developers must declare RTEMS
>> +functions they want to call. This is especially relevant when the
>> +*Bare metal Rust*  approach is used.
> Would a simple status summary at the start be useful? I am not sure after
> reading this if Rust is production ready, experimental or something else?

I would say "The use of Rust is uncomfortable at the current state. 
Moreover, calling RTEMS functions is not pointer safe due to the current 
lack of a wrapper library."

Yet, I am unsure whether to write this as the first two sentences of the 
Rust chapter. The paragaph above is already in the first section a user 
would read.

Greetings,
Frank

> Chris
> 
>> +
>> +.. toctree::
>> +
>> +    bare-metal

-- 
embedded brains GmbH & Co. KG
Herr Frank KÜHNDEL
Dornierstr. 4
82178 Puchheim
Germany
email: frank.kuehndel at embedded-brains.de
phone:  +49-89-18 94 741 - 23
mobile: +49-176-15 22 06 - 11

Registergericht: Amtsgericht München
Registernummer: HRA 117265
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/



More information about the devel mailing list