Non-constant formatting args appear to cause panic in #![no_std] environment

⚓ Rust    📅 2026-02-24    👤 surdeus    👁️ 6      

surdeus

I've been experimenting with kernel-level programming in Rust, and I'm running into a weird issue with printing output over a serial port. Using the RISC-V SBI, I implemented a writer for the SBI debug console as follows:

struct SbiDebugConsole;

impl fmt::Write for SbiDebugConsole {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        // We need to convert the virtual address at which `s` is located into a physical address which we can pass to
        // the SBI.
        let executable_address_response = EXECUTABLE_ADDRESS_REQUEST.get_response().unwrap();
        let s_addr = s.as_ptr().addr()
                .wrapping_sub(executable_address_response.virtual_base() as usize)
                .wrapping_add(executable_address_response.physical_base() as usize);

        // Use assembly to directly call up to the SBI.
        let (error, value): (usize, usize);
        unsafe {
            asm!(
            "ecall",
            in("a7") 0x4442434e,
            in("a6") 0,
            inlateout("a0") s.len() => error,
            inlateout("a1") s_addr => value,
            in("a2") 0,
                );
        }

        if error != 0 || value != s.len() {
            Err(fmt::Error)
        } else {
            Ok(())
        }
    }
}

Using this implementation, I can do things like writeln!(&mut SbiDebugConsole, "foo");. The problem, however, comes when I try to pass non-constant formatting arguments to writeln!. For instance, if I write

writeln!(&mut SbiDebugConsole, "foo");
writeln!(&mut SbiDebugConsole, "num: {}", 0xdeadbeef);
writeln!(&mut SbiDebugConsole, "bar");

everything works as expected, and all three lines are printed. If, however, I instead write

writeln!(&mut SbiDebugConsole, "foo");
let i = 0xdeadbeef;
writeln!(&mut SbiDebugConsole, "num: {}", i);
writeln!(&mut SbiDebugConsole, "bar");

my program appears to panic part-way through, and the output through the serial port reads only

foo
num: 

with the number and the final string bar both absent. Here is a link to the project of which this code is a part, in case it's helpful. I have stepped through the code with GDB, and my Write implementation does not appear to be panicking, so I can only assume that some code in core is panicking somewhere.

11 posts - 4 participants

Read full topic

🏷️ Rust_feed