Pre RFC: Re-implement inline assembly functions in Rust, publish as stand-alone crate

Summary

To define in-line assembly functions, such as those found in libsel4/sel4_arch_include/aarch64/sel4/sel4_arch/syscalls.h, using rust code.

Motivation

In the context of there being a desire to see development of seL4 systems using Rust, a pre-RFC for which can be found here, it might make sense that early efforts include re-implementing C code in Rust where it is straight-forward and uncomplicated. The task of re-implementing in-line assembly is one area that this would make sense.

Guide-level explanation

Instead of:

static inline void arm_sys_send(seL4_Word sys, seL4_Word dest, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1,
                                seL4_Word mr2, seL4_Word mr3)
{
    register seL4_Word destptr asm("x0") = dest;
    register seL4_Word info asm("x1") = info_arg;

    /* Load beginning of the message into registers. */
    register seL4_Word msg0 asm("x2") = mr0;
    register seL4_Word msg1 asm("x3") = mr1;
    register seL4_Word msg2 asm("x4") = mr2;
    register seL4_Word msg3 asm("x5") = mr3;

    /* Perform the system call. */
    register seL4_Word scno asm("x7") = sys;
    asm volatile(
        "svc #0"
        : "+r"(destptr), "+r"(msg0), "+r"(msg1), "+r"(msg2),
        "+r"(msg3), "+r"(info)
        : "r"(scno)
    );
}

use:

#[no_mangle]
#[inline(always)]
pub fn arm_sys_send(sys: usize, dest: usize, info_arg: usize, mr0: usize, mr1: usize, mr2: usize, mr3: usize) {
    unsafe {
        asm!(
            "mov x0, {dest_ptr}",
            "mov x1, {info}",
            "mov x2, {msg0}",
            "mov x3, {msg1}",
            "mov x4, {msg2}",
            "mov x5, {msg3}",
            "mov x7, {scno}",
            "svc #7",
            dest_ptr = in(reg) dest.0,
            info = in(reg) info.0,
            msg0 = in(reg) mr0.0,
            msg1 = in(reg) mr1.0,
            msg2 = in(reg) mr2.0,
            msg3 = in(reg) mr3.0,
            scno = in(reg) sys.0,
            options(nomem),

        )
    }
}

TODO: Where to put the in-line implementations? Into a crates.io published crate? Move to a seperate repository?

Reference level explanation

TODO

Drawbacks

If there is no intention to support using Rust for developing on seL4, there is no benefit to this.

  • There currently generated rust wrappers that call this code.
  • IDE integration: This may break IDE tooling. For example, “go to definition” in a C-context
  • Talent pool: I immagine there are fewer people willing and able to work with, and maintain, this section of the code-base if it’s implemented in Rust instead of C
  • Linking: Linking/inlining these function “Just Works^TM” with the current build system. Linking in an implementation from a Rust library is perhaps non-trivial.
  • Rusts inline assembly syntax is unstable, though this would only be a maintenance issue if seL4 would desire to use a new syntax

Rational Alternatives

Inline this RFC into a “general rust support” RFC: Pre-RFC: To effortlessly develop seL4 systems in rust

Prior art

  • This has already been done for some architechtures in the Robigalia project, showing that it’s both a desired and feasible thing to do.

Unresolved questions

Future Possibilities

Progressively migrate other sections of libsel4 to Rust

I’ve had a go at putting together a proof of concept. Implementing arm_sys_send in rust, and linking that to libsel4. Haven’t made much progress yet, but the goal is to get that sorted, then run the test manifest simulation.

I put both the rust and the C function into godbolt, and the assembly output appears to be equivalent. That level of analysis is new to me, so I can’t say it is equivalent with much confidence.

Just to make sure: you’re aware of the rust syscall stub generator in sel4lib?

I was aware of that script, but I was under the impression that the inline assembly functions weren’t a generator output, but wrather, called by wrappers that this generator tool outputs. Am I mistaken?

No, I think you’re correct, just wanted to make sure you’ve seen what is there and what it would interface to.

From the Rust perspective, I think it makes sense to do this. From the maintenance perspective however, it is duplication. Not all duplication is necessarily bad, maybe it could be used for cross testing, a bit like compiler output checking by running multiple compilers, but it is definitely something we need to think about.

This has been discussed before (I’ll have a look if I can find it). I think the main outcome of the discussion was that the ideal solution would be to generate inline assembly stubs in both languages from a common source, i.e. to extend the xml description we have so far to cover the ABI, not the API.

That is a bigger job, and maybe we shouldn’t let the perfect stand in the way of any progress at all. To do this extension of the xml description, it’d probably be quite useful to actually have a full implementation for at least two languages.

What do others think about this?

Edit: link to a previous discussion on this.