Hello Joel, On 12/20/23 23:37, Joel Sherrill wrote:
Karel Gardas posted in February that he has Rust on RTEMS on an arm.
This is one email from that thread: https://lists.rtems.org/pipermail/devel/2023-March/074532.html
Frank. Are there instructions on building the tools chain somewhere?
I attach a file with instructions which I just compiled from my notices (my Christmas gift to you ;-) ). I have not tested these instructions (again) but I hope they will give you a hint how it did it. I attach them as file to avoid my mail program inserts line breaks.
In case you or anyone else gives these instructions a try, I will be happy for all feedback. The documentation I want to write for the User Manual (if no one else does it before me or has a better approach) would closely follow the steps in the attached file.
And is Jan Sommer part of the DLR Rust on RTEMS project?
I met Jan at ESA ADCSS 2023 at Nordwijk. I prefer Jan answers your question as I do not want to make anything public without prior agreement from DLR.
Greetings, fk
--joel On Wed, Dec 20, 2023, 3:59 PM Frank Kühndel < frank.kuehn...@embedded-brains.de> wrote:Hello Dwaine, On 12/20/23 20:41, Molock, Dwaine S. (GSFC-5820) wrote: > Hello, > > Has anyone been able to execute Rust on RTEMS? Yes – to use RTEMS from within a Rust application, with #![no_std] #![no_main] > > If so, is there a how to guide and what architecture and development hardware was used? I have not yet found time to write a documentation despite I want to do so. Sorry for this. Ferrous Systems first extended Rust to run on Gaisler SPARC bare metal and then they figured it works with RTEMS 5 from Gaisler, too. Their documentation is here: https://github.com/ferrous-systems/sparc-experiments/ I did run my examples only on simulators. I tried two architectures with RTEMS 6: Leon3 and RISC-V. Greetings, Frank -- embedded brains GmbH & Co. KG Herr Frank KÜHNDEL Dornierstr. 4 82178 Puchheim Germany email:frank.kuehn...@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/ _______________________________________________ users mailing list users@rtems.org http://lists.rtems.org/mailman/listinfo/users
-- embedded brains GmbH & Co. KG Herr Frank KÜHNDEL Dornierstr. 4 82178 Puchheim Germany email: frank.kuehn...@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/
Use Rust with RTEMS =================== 2023-Dec-22 Frank Kühndel, embedded brains GmbH & Co. KG This text describes how I used Rust with RTEMS. This is from my notices, I have not checked these instructions again and they come without any grantees. I intent to write a (better) how-to for the RTEMS User Manual as soon as I find some time for it. These instructions are for two Hello-World programs, one for SPARC Leon3 and the other for RISC-V. In both cases, the Rust program use `printk()` from RTEMS to print text to the console. The basic steps are these: * Compile the Rust code containing `main()` into a static library using the Rust compiler. * Compile the RTEMS configuration in `Init.c` into an object file using the gcc from the RTEMS tool chain. * Finally link the static library with the Rust code, the RTEMS init configuration and the RTEMS OS together into one single executable. * Run the executable on a simulator. Note, the Rust SPARC support for Leon3/4/5 is rather new and requires the nightly build of the Rust compiler. My whole work was triggered and inspired by a presentation made by Jonathan Pallant from Ferrous Systems GmbH on ESA Software Product Assurance Workshop 2023: "Using Rust for mission critical systems" https://www.cosmos.esa.int/documents/10939403/13948935/1_Jonathan_Pallant_Using+Rust+for+Mission+Critical+Systems+v5.pdf/12be67e0-de49-3baf-4c00-d797784c6b6a?t=1695808956535 Moreover, he created https://github.com/ferrous-systems/sparc-experiments/ Essentially, Ferrous Systems has certified the open source Rust compiler for ISO 26262 (ASIL D) as a product named ferrocene. There is one known Bug in the examples below: `panic()` always prints "panic occured!" instead of the panic message. If you have a fix, I will be happy to use it for the documentation. Setup RTEMS and Rust ==================== I used an OpenSUSE Leap 15.5 container to have clean environment. I installed the patterns devel_basis and devel_C_C++ as well as the packages gzip, python3 and qemu-extra. To use Python 3 as `python` OpenSUSE requires this command: ``` # update-alternatives --install /usr/bin/python python /usr/bin/python3 20 ``` Moreover, I created a user "ferris" to avoid working as root: ``` # useradd -c "Build User" -g "users" -d "/home/ferris" --create-home "ferris" ``` Install RTEMS Tools ------------------- I needed to install the RTEMS 6 tool chain for "sparc" and "riscv" using the RTEMS source builder. I assume you how know how to do this. I installed to prefix `/opt/rtems/6` and added it to the PATH environment variable: ``` # su ferris > echo "export PATH=/opt/rtems/6/bin:${PATH}" >>~/.bashrc ``` Install and Setup Rust ---------------------- I installed rust from the web-page: ``` # su ferris > curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh Rustup metadata and toolchains will be installed into the Rustup home directory, located at: /home/ferris/.rustup This can be modified with the RUSTUP_HOME environment variable. The Cargo home directory is located at: /home/ferris/.cargo This can be modified with the CARGO_HOME environment variable. The cargo, rustc, rustup and other commands will be added to Cargo's bin directory, located at: /home/ferris/.cargo/bin This path will then be added to your PATH environment variable by modifying the profile files located at: /home/ferris/.profile /home/ferris/.bashrc You can uninstall at any time with rustup self uninstall and these changes will be reverted. ``` At this point it is the best to logout and login again. ``` # su ferris > rustup update > cargo --version cargo 1.73.0 (9c4383fb5 2023-08-26) > sparc-rtems6-gcc --version sparc-rtems6-gcc (GCC) 12.3.1 20231012 (RTEMS 6, RSB 103006fc0bdc6eff7760cb74f15bc16ac4238087-modified, Newlib fbc5496) [...] ``` Install RTEMS ------------- ``` # su ferris > cd > git clone git://git.rtems.org/rtems.git > cd rtems > cat >config.ini <<"EOF" [sparc/leon3] RTEMS_SMP = True [riscv/rv64imafdc] EOF > ./waf configure --prefix=/opt/rtems/6 > ./waf > ./waf install ``` I did run some RTEMS tests to make sure the installation and the simulators are working: ``` > 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 ``` Rust Hello World with RTEMS on SPARC ==================================== I needed to use the Rust nightly build because the support for Gaisler LEON3/4/5 was added Jul 2023 and is not yet available in the stable Rust: ``` # su ferris > cd > rustup toolchain add nightly > rustup component add rust-src --toolchain=nightly ``` I created a simple RTEMS `init.c` to configure RTEMS in a new directory: ``` # su ferris > cd > 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 ``` I created a new Rust project (still in `~/example-rust`): ``` > cargo new --lib --vcs=none rust-sparc > cd rust-sparc > sed -i '/^#/ a \\n[lib]\ncrate-type = ["staticlib"]' Cargo.toml ``` I created the Rust application code (still in `~/example-rust/rust-sparc`): ``` > cat >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, ...) -> !; } /// 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); } } /// 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) -> ! { let mut message = "panic occured!"; if let Some(s) = panic.payload().downcast_ref::<&str>() { message = *s; } 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 ``` I created a configuration file for Cargo (still in `~/example-rust/rust-sparc`): ``` > mkdir .cargo > cat >.cargo/config.toml <<"EOF" # 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 = ["sparc-unknown-none-elf"] [unstable] build-std = ["core"] EOF ``` Build and Run on SPARC ---------------------- I compiled the Rust source file into a static library (still in `~/example-rust/rust-sparc`): ``` > cargo +nightly build --target=sparc-unknown-none-elf ``` It should create `~/example-rust/rust-sparc/target/sparc-unknown-none-elf/debug/librust_sparc.a` I compiled the RTEMS `init.c` file and linked everything together into an executable: ``` > cd ~/example-rust > 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 -qnolinkcmds -T linkcmds.leon3 init_sparc.o > -Lrust-sparc/target/sparc-unknown-none-elf/debug -lrust_sparc > -orust-sparc.exe $(pkg-config --libs ${PKG_CONFIG_SPARC}) ``` Then I was able to run the executable (still in `~/example-rust`): ``` > rtems-run --rtems-bsp=leon3-sis rust-sparc.exe ``` Rust Hello World with RTEMS on RISC-V ===================================== This is very similar to the SPARC variant above with tiny changes. Moreover, one does not need a nightly build of the Rust tools. I reused the directory `~/example-rust` and the file RTEMS `init.c` which I created at the beginning of the SPARC variant above. Next, I created a new Rust project: ``` # su ferris > cd ~/example-rust > cargo new --lib --vcs=none rust-riscv > cd rust-riscv > sed -i '/^#/ a \\n[lib]\ncrate-type = ["staticlib"]' Cargo.toml ``` I created the Rust application code (still in `~/example-rust/rust-riscv`): ``` > cat >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) -> ! { let mut message = "panic occured!"; if let Some(s) = panic.payload().downcast_ref::<&str>() { message = *s; } 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 ``` I created a configuration file for Cargo (still in `~/example-rust/rust-riscv`): ``` > mkdir .cargo > cat >.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 " [build] target = ["riscv64gc-unknown-none-elf"] [unstable] build-std = ["core"] EOF ``` As a side node, to get an idea what hardware Rust supports and some more information try these (or similar) commands: * `rustc --print target-list` * `rustc --target=riscv64gc-unknown-none-elf --print target-features` * `rustc --target=riscv64gc-unknown-none-elf --print target-cpus` Build and Run on RISC-V ----------------------- First, I needed to download some additional files for this target: ``` > rustup target add riscv64gc-unknown-none-elf ``` I compiled the Rust source file into a static library (still in `~/example-rust/rust-riscv`): ``` > cargo build --target=riscv64gc-unknown-none-elf ``` It should create `target/riscv64gc-unknown-none-elf/debug/librust_riscv.a` I compiled the RTEMS `init.c` file and linked everything together into an executable: ``` > cd ~/example-rust > 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 > -Lrust-riscv/target/riscv64gc-unknown-none-elf/debug -lrust_riscv > -orust_riscv.exe $(pkg-config --variable=ABI_FLAGS ${PKG_CONFIG_RISCV}) > $(pkg-config --libs ${PKG_CONFIG_RISCV}) ``` Then I was able to run the executable (still in `~/example-rust`): ``` > rtems-run --rtems-bsp=rv64imafdc rust_riscv.exe ``` -- embedded brains GmbH & Co. KG Herr Frank KÜHNDEL Dornierstr. 4 82178 Puchheim Germany email: frank.kuehn...@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/
_______________________________________________ users mailing list users@rtems.org http://lists.rtems.org/mailman/listinfo/users