From: Simon Glass <simon.glass@canonical.com> Add a #![no_std] Rust equivalent of the C ulib demo, compiled to an object file with rustc and linked into U-Boot via the existing u-boot-link mechanism. The Rust demo calls the same C helpers (demo_show_banner, demo_show_footer, demo_add_numbers) via FFI and produces identical output, so assert_demo_output() works unchanged. Use core::ptr::addr_of!() rather than a reference cast to access the extern static version_string, since the compiler cannot prove that an extern static is non-null and would emit a call to an undefined panic symbol. Add CONFIG_RUST_EXAMPLES Kconfig option to gate the Rust examples. When enabled, rustc must be available with the appropriate target for the architecture. Clear MAKEFLAGS when invoking rustc so that it does not inherit make's --jobserver-auth file descriptors, which would produce a spurious warning on every compilation. Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- examples/Kconfig | 13 +++++++++ examples/ulib/rust_demo.rs | 55 +++++++++++++++++++++++++++++++++++ scripts/Makefile.ulib-example | 17 +++++++++++ 3 files changed, 85 insertions(+) create mode 100644 examples/ulib/rust_demo.rs diff --git a/examples/Kconfig b/examples/Kconfig index 5738d555d22..7f099808908 100644 --- a/examples/Kconfig +++ b/examples/Kconfig @@ -9,6 +9,19 @@ config EXAMPLES U-Boot provides an legacy API for standalone applications. Examples are provided in directory examples/. +config RUST_EXAMPLES + bool "Build Rust example programs" + depends on EXAMPLES + help + Build example programs written in Rust alongside the C + examples. The Rust demo calls the same C helpers via FFI + and produces identical output. + + Requires a Rust toolchain (rustc) with the appropriate + cross-compilation target for the architecture, e.g. + x86_64-unknown-none for x86_64 or aarch64-unknown-none + for ARM64. + config EXAMPLES_STANDALONE bool "Compile standalone examples" depends on !SANDBOX diff --git a/examples/ulib/rust_demo.rs b/examples/ulib/rust_demo.rs new file mode 100644 index 00000000000..7a85658520d --- /dev/null +++ b/examples/ulib/rust_demo.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Rust demo program showing U-Boot library functionality +// +// Demonstrates calling C helper functions from Rust via FFI, producing +// identical output to demo.c so assert_demo_output() works unchanged. +// +// Copyright 2026 Canonical Ltd. +// Written by Simon Glass <simon.glass@canonical.com> + +#![no_std] +#![no_main] + +use core::ffi::c_int; + +extern "C" { + fn printf(fmt: *const u8, ...) -> c_int; + fn demo_show_banner(); + fn demo_show_footer(); + fn demo_add_numbers(a: c_int, b: c_int) -> c_int; + static version_string: u8; +} + +#[no_mangle] +pub extern "C" fn ulib_has_main() -> bool { + true +} + +fn demo_run() -> c_int { + unsafe { + demo_show_banner(); + // Use addr_of!() rather than &version_string to avoid a + // null-pointer check: &T must be non-null, but the compiler + // cannot prove that for an extern static, so it emits a call + // to an undefined panic symbol that crashes ld.bfd on aarch64. + printf( + b"U-Boot version: %s\n\0".as_ptr(), + core::ptr::addr_of!(version_string), + ); + printf(b"\n\0".as_ptr()); + demo_add_numbers(42, 13); + demo_show_footer(); + } + 0 +} + +#[no_mangle] +pub extern "C" fn main() -> c_int { + demo_run() +} + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/scripts/Makefile.ulib-example b/scripts/Makefile.ulib-example index 796b74b0c14..18d526f5b6b 100644 --- a/scripts/Makefile.ulib-example +++ b/scripts/Makefile.ulib-example @@ -19,11 +19,28 @@ PHONY += examples_$(EXAMPLE_ARCH) ULIB_EXAMPLES := demo +# --- Rust examples --- +RUSTC := rustc +RUST_TARGET := $(RUST_TARGET_$(EXAMPLE_ARCH)) + +ifeq ($(CONFIG_RUST_EXAMPLES),y) +ULIB_EXAMPLES += rust-demo +endif + quiet_cmd_u-boot-example = LD $@ cmd_u-boot-example = $(call u-boot-link,$(example-objs),$@.map) +quiet_cmd_rustc_obj = RUSTC $@ + cmd_rustc_obj = \ + mkdir -p $(dir $@) && \ + MAKEFLAGS= $(RUSTC) --edition 2021 --emit=obj -o $@ --target=$(RUST_TARGET) $< + +examples/ulib/rust_demo.o: examples/ulib/rust_demo.rs FORCE + $(call if_changed,rustc_obj) + # Per-example object lists (matches examples/ulib/Kbuild) example-demo-objs := examples/ulib/demo.o examples/ulib/demo_helper.o +example-rust-demo-objs := examples/ulib/rust_demo.o examples/ulib/demo_helper.o # Generate link rule for each example define example_link_rule -- 2.43.0