Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking Issue for the C-cmse-nonsecure-call ABI #81391

Open
2 tasks
hug-dev opened this issue Jan 25, 2021 · 11 comments
Open
2 tasks

Tracking Issue for the C-cmse-nonsecure-call ABI #81391

hug-dev opened this issue Jan 25, 2021 · 11 comments
Labels
A-codegen Area: Code generation C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-abi_c_cmse_nonsecure_call `#![feature(abi_c_cmse_nonsecure_call)]` O-Arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. WG-embedded Working group: Embedded systems

Comments

@hug-dev
Copy link
Contributor

hug-dev commented Jan 25, 2021

This is a tracking issue for the PR #81346.
The feature gate for the issue is #![feature(abi_c_cmse_nonsecure_call)].

Description

The TrustZone-M feature is available for targets with the Armv8-M architecture profile (thumbv8m in their target name).
LLVM, the Rust compiler and the linker are providing support for the TrustZone-M feature.

One of the things provided, with this unstable feature, is the C-cmse-nonsecure-call function ABI. This ABI is used on function pointers to non-secure code to mark a non-secure function call (see section 5.5 for details).

With this ABI, the compiler will do the following to perform the call:

  • save registers needed after the call to Secure memory
  • clear all registers that might contain confidential information
  • clear the Least Significant Bit of the function address
  • branches using the BLXNS instruction

To avoid using the non-secure stack, the compiler will constrain the number and type of parameters/return value.

The extern "C-cmse-nonsecure-call" ABI is otherwise equivalent to the extern "C" ABI.

Example

#![no_std]
#![feature(abi_c_cmse_nonsecure_call)]

#[no_mangle]
pub fn call_nonsecure_function(addr: usize) -> u32 {
    let non_secure_function =
        unsafe { core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn() -> u32>(addr) };
    non_secure_function()
}
$ rustc --emit asm --crate-type lib --target thumbv8m.main-none-eabi function.rs

call_nonsecure_function:
        .fnstart
        .save   {r7, lr}
        push    {r7, lr}
        .setfp  r7, sp
        mov     r7, sp
        .pad    #16
        sub     sp, #16
        str     r0, [sp, #12]
        ldr     r0, [sp, #12]
        str     r0, [sp, #8]
        b       .LBB0_1
.LBB0_1:
        ldr     r0, [sp, #8]
        push.w  {r4, r5, r6, r7, r8, r9, r10, r11}
        bic     r0, r0, #1
        mov     r1, r0
        mov     r2, r0
        mov     r3, r0
        mov     r4, r0
        mov     r5, r0
        mov     r6, r0
        mov     r7, r0
        mov     r8, r0
        mov     r9, r0
        mov     r10, r0
        mov     r11, r0
        mov     r12, r0
        msr     apsr_nzcvq, r0
        blxns   r0
        pop.w   {r4, r5, r6, r7, r8, r9, r10, r11}
        str     r0, [sp, #4]
        b       .LBB0_2
.LBB0_2:
        ldr     r0, [sp, #4]
        add     sp, #16
        pop     {r7, pc}

Steps

@hug-dev hug-dev added the C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC label Jan 25, 2021
@jonas-schievink jonas-schievink added F-abi_c_cmse_nonsecure_call `#![feature(abi_c_cmse_nonsecure_call)]` O-Arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state WG-embedded Working group: Embedded systems labels Jan 25, 2021
@nagisa
Copy link
Member

nagisa commented Jan 26, 2021

What's the name of the actual underlying calling convention? Is it AAPCS? I think the extern name should contain it too somehow.

@hug-dev
Copy link
Contributor Author

hug-dev commented Jan 26, 2021

What's the name of the actual underlying calling convention?

It will use the C convention ultimately, the current implementation maps it to llvm::CCallConv (I guess similar than AAPCS as this feature is only available on Arm processors?).
Do you mean that because it might be possible to have the cmse_nonsecure_call feature available for other ABIs as well?

I think restricting it to only ever use the C ABI is not a bad thing: this is used to switch to functions that are defined in other executable files that could have been written in any programming language.

@nagisa
Copy link
Member

nagisa commented Jan 26, 2021

Well, what I really want is for the underlying ABI to be explicit in the ABI string, whatever it is, so that it is more obvious that a transmute as given in the example above is… valid. It would also, as you mention, enable us to add non-secure options for other calling conventions if necessary.

So a couple of proposals: C_cmse_nonsecure or cmse_nonsecure_C.

@hug-dev
Copy link
Contributor Author

hug-dev commented Jan 26, 2021

Ok makes sense! Will modify the implementation PR and this with the C in front: extern "C-cmse-nonsecure-call".

@hug-dev hug-dev changed the title Tracking Issue for the cmse-nonsecure-call ABI Tracking Issue for the C-cmse-nonsecure-call ABI Jan 27, 2021
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jul 19, 2024
…rror-messages, r=oli-obk

`C-cmse-nonsecure-call`: improved error messages

tracking issue: rust-lang#81391
issue for the error messages (partially implemented by this PR): rust-lang#81347
related, in that it also deals with CMSE: rust-lang#127766

When using the `C-cmse-nonsecure-call` ABI, both the arguments and return value must be passed via registers. Previously, when violating this constraint, an ugly LLVM error would be shown. Now, the rust compiler itself will print a pretty message and link to more information.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jul 19, 2024
Rollup merge of rust-lang#127814 - folkertdev:c-cmse-nonsecure-call-error-messages, r=oli-obk

`C-cmse-nonsecure-call`: improved error messages

tracking issue: rust-lang#81391
issue for the error messages (partially implemented by this PR): rust-lang#81347
related, in that it also deals with CMSE: rust-lang#127766

When using the `C-cmse-nonsecure-call` ABI, both the arguments and return value must be passed via registers. Previously, when violating this constraint, an ugly LLVM error would be shown. Now, the rust compiler itself will print a pretty message and link to more information.
@folkertdev
Copy link
Contributor

folkertdev commented Jul 30, 2024

Request for Stabilization

Summary

We propose to stabilize the C-cmse-nonsecure-call ABI. It can only be used in function pointer types, never in an actual *extern "C-cmse-nonsecure-call" {} block. Such function pointers are typically received via FFI.

Usage example

https://godbolt.org/z/KT6hc5Y7W

// `cargo build --target thumbv8m.main-none-eabi`
#![feature(abi_c_cmse_nonsecure_call)]
#![no_std]

#[no_mangle]
pub fn call_nonsecure(f: unsafe extern "C-cmse-nonsecure-call" fn(u8, u16, u32) -> f32) -> f32 {
    unsafe { f(1, 2, 3) }
}

Which produces this LLVM IR:

; Function Attrs: nounwind
define dso_local float @call_nonsecure(ptr %f) unnamed_addr #0 !dbg !5 {
start:
  %_0 = call float %f(i8 zeroext 1, i16 zeroext 2, i32 3) #1, !dbg !10
  ret float %_0, !dbg !11
}

attributes #0 = { nounwind "frame-pointer"="all" "target-cpu"="generic" }
attributes #1 = { nounwind "cmse_nonsecure_call" }

Which produces this assembly:

call_nonsecure:
        push    {r7, lr}
        mov     r7, sp
        mov     r3, r0
        movs    r0, #1
        movs    r1, #2
        movs    r2, #3
        push.w  {r4, r5, r6, r7, r8, r9, r10, r11}
        bic     r3, r3, #1
        sub     sp, #136
        vlstm   sp
        mov     r4, r3 ; <- All unused registers get cleared, to not leak information
        mov     r5, r3
        mov     r6, r3
        mov     r7, r3
        mov     r8, r3
        mov     r9, r3
        mov     r10, r3
        mov     r11, r3
        mov     r12, r3
        msr     apsr_nzcvq, r3
        blxns   r3 ; <- the expected non-secure call instruction
        vlldm   sp
        add     sp, #136
        pop.w   {r4, r5, r6, r7, r8, r9, r10, r11}
        pop     {r7, pc}

Error messages

The calling requirements for this ABI are checked within rustc to produce good error messsages.

#![feature(abi_c_cmse_nonsecure_call)]
#![no_std]

#[no_mangle]
pub fn call_nonsecure(f: unsafe extern "C-cmse-nonsecure-call" fn(u64, u64, u64) -> (u64, u64)) {
    unsafe { f(1, 2, 3) };
}

Produces the following errors:

error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
 --> <source>:5:77
  |
5 | pub fn call_nonsecure(f: unsafe extern "C-cmse-nonsecure-call" fn(u64, u64, u64) -> (u64, u64)) {
  |                                                                             ^^^ this argument doesn't fit in the available registers
  |
  = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers

error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
 --> <source>:5:85
  |
5 | pub fn call_nonsecure(f: unsafe extern "C-cmse-nonsecure-call" fn(u64, u64, u64) -> (u64, u64)) {
  |                                                                                     ^^^^^^^^^^ this type doesn't fit in the available registers
  |
  = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
  = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0798`.

Documentation

Tests

Test cases are in

https://github.com/rust-lang/rust/tree/master/tests/ui/cmse-nonsecure/cmse-nonsecure-call

  • the abi is not allowed in extern blocks or extern fn definitions (and therefore is only allowed in function pointers)
  • part of this ABI is that arguments and return values must be passed via registers. This is validated pre-monomorphization so that good error messages can be generated.
  • to make the above restriction work, generics are not allowed in signatures that use this abi. That is fine because these are (effectively) external C function, so generics are not meaningful.

The tests in the (as yet unmerged) PR for cmse-nonsecure-entry validate the assembly output of this ABI.

C examples

Clang: https://godbolt.org/z/7ch3xcz96
GCC: https://godbolt.org/z/16arxab5x

@tdittr
Copy link
Contributor

tdittr commented Jul 30, 2024

This tracking issues seems to be missing some tags compared to #75835

@rustbot label +T-compiler +T-lang +A-codegen

@rustbot rustbot added A-codegen Area: Code generation T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jul 30, 2024
@jieyouxu
Copy link
Member

jieyouxu commented Aug 4, 2024

Nominating for both T-lang and T-compiler discussion: there is a request for the stabilization of the C-cmse-nonsecure-call ABI (posted above at #81391 (comment)), there's also the seemingly related #[cmse_nonsecure_entry] attribute (#75835). This is mostly nominated for several reasons stated below.

For T-compiler:

  • Procedure questions:
    • Does this need an MCP/FCP for stabilization, or does this need further design?
    • Does this need a joint T-compiler/T-lang FCP?
  • We should help the people working on cmse-related things to find knowledgeable reviewers / domain experts who can help with reviewing the changes, or otherwise provide advice on how to split related PRs into smaller PRs that reviewers feel more confident to review. add extern "C-cmse-nonsecure-entry" fn  #127766 already got rerolled a bunch of times (currently, the dice landed on Wesley ^^).

For T-lang:

  • Procedure questions:
    • Does this need T-lang sign-off, like a T-lang FCP or a joint T-lang/T-compiler FCP?

For both T-compiler and T-lang:

  • Is the cmse-related efforts being tracked anywhere?

@rustbot labels +I-compiler-nominated +I-lang-nominated

@rustbot rustbot added I-compiler-nominated Nominated for discussion during a compiler team meeting. I-lang-nominated Nominated for discussion during a lang team meeting. labels Aug 4, 2024
@apiraino
Copy link
Contributor

Discussed in t-compiler triage on Zulip. Probably T-lang could be decide if we're ok in principle with having such an abi (the compiler should then just need to pass to LLVM the right info).

@rustbot label -I-compiler-nominated

@rustbot rustbot removed the I-compiler-nominated Nominated for discussion during a compiler team meeting. label Aug 15, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Sep 9, 2024
…piler-errors

fix ICE in CMSE type validation

fixes rust-lang#129983

tracking issue: rust-lang#81391

r? `@compiler-errors`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Sep 9, 2024
…piler-errors

fix ICE in CMSE type validation

fixes rust-lang#129983

tracking issue: rust-lang#81391

r? ``@compiler-errors``
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Sep 9, 2024
Rollup merge of rust-lang#130064 - folkertdev:fix-issue-129983, r=compiler-errors

fix ICE in CMSE type validation

fixes rust-lang#129983

tracking issue: rust-lang#81391

r? ``@compiler-errors``
tgross35 added a commit to tgross35/rust that referenced this issue Sep 24, 2024
…ouxu

Improve assembly test for CMSE ABIs

Tracking issues: rust-lang#75835 rust-lang#81391

This ensures the code-gen for these ABIs does not change silently. There is a small chance that this code-gen might change, however even GCC (https://godbolt.org/z/16arxab5x and https://godbolt.org/z/16arxab5x) generates almost the same assembly for these ABIs. I hope the notes in the comments should help fix the tests if it ever breaks.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Sep 25, 2024
Rollup merge of rust-lang#130752 - tdittr:cmse-assembly-tests, r=jieyouxu

Improve assembly test for CMSE ABIs

Tracking issues: rust-lang#75835 rust-lang#81391

This ensures the code-gen for these ABIs does not change silently. There is a small chance that this code-gen might change, however even GCC (https://godbolt.org/z/16arxab5x and https://godbolt.org/z/16arxab5x) generates almost the same assembly for these ABIs. I hope the notes in the comments should help fix the tests if it ever breaks.
@nikomatsakis
Copy link
Contributor

I think this feature merits an RFC prior to stabilizing. It goes beyond "just another ABI", it requires specialized type-checking and includes some attributes that go along with it. I think an RFC is warranted showing the overall design and how it fits together (I know I myself am confused).

@scottmcm pointed out that they might like the attribute to be namespaced, which seems like the kind of detail I'd rather hammer out in the context of an RFC thread.

I'm 👍 on the idea of supporting these capabilities, though!

@traviscross traviscross removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Oct 16, 2024
@nikomatsakis
Copy link
Contributor

Coming out of the @rust-lang/lang team meeting, our consensus was that an RFC is the right next step.

@traviscross
Copy link
Contributor

To answer the nominated questions:

Does this need T-lang sign-off, like a T-lang FCP...?

Yes. Please tag us on the RFC.

Is the cmse-related efforts being tracked anywhere?

This is the tracking issue, so it'd be the right place for that. I'm unclear whether there's a broader discussion going on somewhere else, e.g. on Zulip, that might have more context. (If anyone here knows of that, please point to it.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-abi_c_cmse_nonsecure_call `#![feature(abi_c_cmse_nonsecure_call)]` O-Arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. WG-embedded Working group: Embedded systems
Projects
None yet
Development

No branches or pull requests

10 participants