Skip to content

Commit 56c5ef8

Browse files
committed
final tweaks
1 parent 75df78e commit 56c5ef8

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

text/0000-cmse-calling-conventions.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
- Feature Name: (fill me in with a unique ident, `my_awesome_feature`)
2-
- Start Date: (fill me in with today's date, YYYY-MM-DD)
1+
- Feature Name: `cmse_nonsecure_entry` and `abi_cmse_nonsecure_call`
2+
- Start Date: 2025-11-24
33
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
44
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
55

@@ -8,6 +8,12 @@
88

99
Support for the `cmse-nonsecure-entry` and `cmse-nonsecure-call` calling conventions on `thumbv8` targets, and a lint preventing (partially) uninitialized values from crossing the security boundary.
1010

11+
The implementation is tracked in:
12+
13+
- https://github.com/rust-lang/rust/issues/75835
14+
- https://github.com/rust-lang/rust/issues/81391
15+
- https://github.com/rust-lang/rust/pull/147697
16+
1117
# Motivation
1218
[motivation]: #motivation
1319

@@ -17,9 +23,9 @@ Trustzone creates a security boundary between a secure and non-secure applicatio
1723

1824
In embedded systems it is common to have an extra physical chip, a secure enclave, to handle secure information. With Trustzone, this additional chip is not needed: a secure enclave is simulated on the main chip instead.
1925

20-
The secure and non-secure applications communicate over an FFI boundary: the two applications run on the same chip and use the same address space, but are not linked together. The cmse calling conventions are used to cross this FFI boundary, and apply restrictions on how it can be crossed.
26+
The secure and non-secure applications communicate over an FFI boundary: the two applications run on the same chip and use the same address space, but are not linked together. The cmse calling conventions are used to cross this FFI boundary, and apply restrictions on how it can be crossed.
2127

22-
Much like how `unsafe` in rust limits where the programmer must be careful not to introduce UB, these special calling conventions clearly mark where secure data might be leaked. They also handle the clearing of registers before the secure boundary is crossed, so that a malicious non-secure application cannot read lingering secure data.
28+
Functions that use these ABIs must be reviewed carefully because they mark where secure data might be leaked. This is analogous to `unsafe` limiting where UB might be introduced in a program. The calling conventions automatically handle the clearing of registers before the secure boundary is crossed, so that a malicious non-secure application cannot read lingering secure data.
2329

2430
Without compiler support it is much harder to know where to focus review effort, and every call that crosses the secure boundary requires inline assembly, which is inconvenient and error-prone.
2531

@@ -29,7 +35,7 @@ Trustzone is growing in availability and use. More and more of the new medium an
2935
# Guide-level explanation
3036
[guide-level-explanation]: #guide-level-explanation
3137

32-
The cmse calling conventions are part of the *Cortex-M Security Extension* that are available on thumbv8 systems. They are used together with Trustzone (hardware isolation) to create more secure embedded applications.
38+
The cmse calling conventions are part of the *Cortex-M Security Extension* that are available on thumbv8 systems. They are used together with Trustzone (hardware isolation) to create more secure embedded applications.
3339

3440
The main idea of Trustzone is to split an embedded application into two executables. The secure executable has access to secrets (e.g. encryption keys), and must be careful not to leak those secrets. The non-secure executable cannot access these secrets or any memory that is marked as secure: the system will raise a SecureFault when a program dereferences a pointer to memory that it does not have access to. In this way a whole class of security issues is prevented in the non-secure app.
3541

@@ -39,7 +45,7 @@ The `cmse-nonsecure-entry` calling convention is used in the secure executable t
3945

4046
The `cmse-nonsecure-call` calling convention is used in the other direction, when the secure executable wants to call into the non-secure executable. This calling convention can only occur on function pointers, not on definitions or extern blocks. The secure executable can acquire a non-secure function pointer via shared memory, or a non-secure callback can be passed to an entry function.
4147

42-
Both calling conventions are based on the platform's C calling convention, but will not use the stack to pass arguments or the return value. In practice that means that the arguments must fit in the 4 available argument registers, and the return value must fit in a single 32-bit register, or be abi-compatible with a 64-bit integer or float. The compiler checks that the signature is valid, and reports an error if not.
48+
Both calling conventions are based on the platform's C calling convention, but will not use the stack to pass arguments or the return value. In practice that means that the arguments must fit in the 4 available argument registers, and the return value must fit in a single 32-bit register, or be abi-compatible with a 64-bit integer or float. The compiler checks that the signature is valid.
4349
# Reference-level explanation
4450
[reference-level-explanation]: #reference-level-explanation
4551

@@ -50,9 +56,9 @@ The `cmse-nonsecure-call` and `cmse-nonsecure-entry` ABIs are only accepted on `
5056

5157
The foundation of the cmse ABIs is the platform's standard AAPCS calling convention. On `thumbv8m` targets `extern "aapcs"` is the default C ABI and equivalent to `extern "C"`.
5258

53-
The `cmse-nonsecure-call` ABI can only be used on function pointers. Using it in for a function definition or extern block emits an error. It is invalid to cast to or from `extern "aapcs"`.
59+
The `cmse-nonsecure-call` ABI can only be used on function pointers. Using it in for a function definition or extern block emits an error. It is invalid to cast to or from `extern "aapcs"`.
5460

55-
The `cmse-nonsecure-entry` ABI is allowed on function definitions, extern blocks and function pointers. It is sound and valid (in some cases even encouraged) to cast such a function to `extern "aapcs"`. Calling the function is valid and will behave as expected in both the secure and non-secure applications. Casting from `extern "aapcs"` to `extern "C"` is invalid.
61+
The `cmse-nonsecure-entry` ABI is allowed on function definitions, extern blocks and function pointers. It is sound and valid (in some cases even encouraged) to cast such a function to `extern "aapcs"`. Calling the function is valid and will behave as expected in both the secure and non-secure applications. Casting from `extern "aapcs"` to `extern "C"` is invalid.
5662

5763
### Argument passing
5864

@@ -108,7 +114,7 @@ LL | extern "cmse-nonsecure-entry" fn return_impl_trait(_: impl Copy) -> impl Co
108114
The `cmse-nonsecure-call` calling convention can only be used on function pointers, which already disallows generics. For `cmse-nonsecure-entry`, it is standard to add a `#[no_mangle]` or similar attribute, which also disallows generics. Explicitly disallowing generics enables the pre-monomorphization layout calculation that is required for good error messages for signatures that use too many registers.
109115
### No C-variadics (currently)
110116

111-
Currently both ABIs disallow the use of c-variadics. For `cmse-nonsecure-entry`, the toolchain actually does not support c-variadic signatures (likely because of how they interact with shim that switches to secure mode), though the specification does not say that explicitly).
117+
Currently both ABIs disallow the use of c-variadics. For `cmse-nonsecure-entry`, the toolchain actually does not support c-variadic signatures (likely because of how they interact with shim that switches to secure mode, though the specification does not say that explicitly).
112118

113119
- clang rejects c-variadic entry functions: https://godbolt.org/z/MaPjzGcE1
114120
- but accepts c-variadic nonsecure calls: https://godbolt.org/z/5rdK58ar4
@@ -274,7 +280,7 @@ For a true ergonomic experience more work is needed, but we believe this can all
274280

275281
Clang and GCC support CMSE using the `__attribute__((cmse_nonsecure_entry))` and `__attribute__((cmse_nonsecure_call))` attributes. As mentioned the ABI restrictions are checked, but only late in the compilation process.
276282

277-
The [`cortex_m`](https://docs.rs/cortex-m/latest/cortex_m/cmse/index.html) crate already provides some primitives for building cmse applications.
283+
The [`cortex_m`](https://docs.rs/cortex-m/latest/cortex_m/cmse/index.html) crate already provides some primitives for building cmse applications, e.g. to query whether a pointer points to secure or non-secure memory.
278284

279285
### Sources
280286

0 commit comments

Comments
 (0)