Skip to content

Commit 867bd42

Browse files
committed
Auto merge of rust-lang#75810 - hug-dev:cmse-nonsecure-entry, r=jonas-schievink
Add support for cmse_nonsecure_entry attribute This pull request adds the `cmse_nonsecure_entry` attribute under an unstable feature. I was not sure if it was fine for me to send directly the pull-request or if I should submit a RFC first. I was told on Zulip that it was fine to do so but please close it if I need first submit a RFC or follow another process instead. The `cmse_nonsecure_entry` attribute is a LLVM attribute that will be available in LLVM 11. I plan to rebase on the [upgrade PR](rust-lang#73526) once merged to make this one compile. This attribute modifies code generation of the function as explained [here](https://developer.arm.com/documentation/ecm0359818/latest/) to make it work with the TrustZone-M hardware feature. This feature is only available on `thumbv8m` targets so I created an error for that if one tries to use this attribute for another target. I added this attribute in Rust as any other LLVM attribute are added but since this one is target-dependent I am not sure if it was the best thing to do. Please indicate me if you think of other ways, like isolating target-dependent attributes together. ---------------- Tracking issue: rust-lang#75835
2 parents d92d28e + 2588287 commit 867bd42

File tree

25 files changed

+254
-1
lines changed

25 files changed

+254
-1
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
294294
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
295295
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
296296
}
297+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
298+
llvm::AddFunctionAttrString(llfn, Function, const_cstr!("cmse_nonsecure_entry"));
299+
}
297300
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
298301

299302
// Always annotate functions with the target-cpu they are compiled for.

compiler/rustc_codegen_llvm/src/back/write.rs

+7
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
344344
.expect("non-UTF8 diagnostic");
345345
diag_handler.warn(&msg);
346346
}
347+
llvm::diagnostic::Unsupported(diagnostic_ref) => {
348+
let msg = llvm::build_string(|s| {
349+
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
350+
})
351+
.expect("non-UTF8 diagnostic");
352+
diag_handler.err(&msg);
353+
}
347354
llvm::diagnostic::UnknownDiagnostic(..) => {}
348355
}
349356
}

compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub enum Diagnostic<'ll> {
118118
InlineAsm(InlineAsmDiagnostic<'ll>),
119119
PGO(&'ll DiagnosticInfo),
120120
Linker(&'ll DiagnosticInfo),
121+
Unsupported(&'ll DiagnosticInfo),
121122

122123
/// LLVM has other types that we do not wrap here.
123124
UnknownDiagnostic(&'ll DiagnosticInfo),
@@ -159,6 +160,7 @@ impl Diagnostic<'ll> {
159160

160161
Dk::PGOProfile => PGO(di),
161162
Dk::Linker => Linker(di),
163+
Dk::Unsupported => Unsupported(di),
162164

163165
_ => UnknownDiagnostic(di),
164166
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ pub enum DiagnosticKind {
483483
OptimizationFailure,
484484
PGOProfile,
485485
Linker,
486+
Unsupported,
486487
}
487488

488489
/// LLVMRustDiagnosticLevel

compiler/rustc_codegen_llvm/src/llvm/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &C
3737
}
3838
}
3939

40+
pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) {
41+
unsafe {
42+
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null())
43+
}
44+
}
45+
4046
#[derive(Copy, Clone)]
4147
pub enum AttributePlace {
4248
ReturnValue,

compiler/rustc_error_codes/src/error_codes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ E0770: include_str!("./error_codes/E0770.md"),
458458
E0771: include_str!("./error_codes/E0771.md"),
459459
E0773: include_str!("./error_codes/E0773.md"),
460460
E0774: include_str!("./error_codes/E0774.md"),
461+
E0775: include_str!("./error_codes/E0775.md"),
462+
E0776: include_str!("./error_codes/E0776.md"),
461463
;
462464
// E0006, // merged with E0005
463465
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M
2+
extension.
3+
4+
Erroneous code example:
5+
6+
```compile_fail,E0775
7+
#![feature(cmse_nonsecure_entry)]
8+
9+
#[cmse_nonsecure_entry]
10+
pub extern "C" fn entry_function() {}
11+
```
12+
13+
To fix this error, compile your code for a Rust target that supports the
14+
TrustZone-M extension. The current possible targets are:
15+
* `thumbv8m.main-none-eabi`
16+
* `thumbv8m.main-none-eabihf`
17+
* `thumbv8m.base-none-eabi`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
`#[cmse_nonsecure_entry]` functions require a C ABI
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0776
6+
#![feature(cmse_nonsecure_entry)]
7+
8+
#[no_mangle]
9+
#[cmse_nonsecure_entry]
10+
pub fn entry_function(input: Vec<u32>) {}
11+
```
12+
13+
To fix this error, declare your entry function with a C ABI, using `extern "C"`.

compiler/rustc_feature/src/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,9 @@ declare_features! (
590590
/// Allows using and casting function pointers in a `const fn`.
591591
(active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
592592

593+
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.
594+
(active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
595+
593596
// -------------------------------------------------------------------------
594597
// feature-group-end: actual feature gates
595598
// -------------------------------------------------------------------------

compiler/rustc_feature/src/builtin_attrs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
349349
experimental!(register_tool),
350350
),
351351

352+
gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
353+
352354
// ==========================================================================
353355
// Internal attributes: Stability, deprecation, and unsafe:
354356
// ==========================================================================

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,7 @@ enum class LLVMRustDiagnosticKind {
11711171
OptimizationFailure,
11721172
PGOProfile,
11731173
Linker,
1174+
Unsupported,
11741175
};
11751176

11761177
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
@@ -1197,6 +1198,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
11971198
return LLVMRustDiagnosticKind::PGOProfile;
11981199
case DK_Linker:
11991200
return LLVMRustDiagnosticKind::Linker;
1201+
case DK_Unsupported:
1202+
return LLVMRustDiagnosticKind::Unsupported;
12001203
default:
12011204
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
12021205
? LLVMRustDiagnosticKind::OptimizationRemarkOther

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ bitflags! {
7979
/// #[ffi_const]: applies clang's `const` attribute to a foreign function
8080
/// declaration.
8181
const FFI_CONST = 1 << 13;
82+
/// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
83+
/// function as an entry function from Non-Secure code.
84+
const CMSE_NONSECURE_ENTRY = 1 << 14;
8285
}
8386
}
8487

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ symbols! {
337337
closure_to_fn_coercion,
338338
cmp,
339339
cmpxchg16b_target_feature,
340+
cmse_nonsecure_entry,
340341
coerce_unsized,
341342
cold,
342343
column,

compiler/rustc_typeck/src/collect.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
25432543
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
25442544
} else if tcx.sess.check_name(attr, sym::used) {
25452545
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
2546+
} else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) {
2547+
if tcx.fn_sig(id).abi() != abi::Abi::C {
2548+
struct_span_err!(
2549+
tcx.sess,
2550+
attr.span,
2551+
E0776,
2552+
"`#[cmse_nonsecure_entry]` requires C ABI"
2553+
)
2554+
.emit();
2555+
}
2556+
if !tcx.sess.target.target.llvm_target.contains("thumbv8m") {
2557+
struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
2558+
.emit();
2559+
}
2560+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
25462561
} else if tcx.sess.check_name(attr, sym::thread_local) {
25472562
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
25482563
} else if tcx.sess.check_name(attr, sym::track_caller) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# `cmse_nonsecure_entry`
2+
3+
The tracking issue for this feature is: [#75835]
4+
5+
[#75835]: https://github.com/rust-lang/rust/issues/75835
6+
7+
------------------------
8+
9+
The [TrustZone-M
10+
feature](https://developer.arm.com/documentation/100690/latest/) is available
11+
for targets with the Armv8-M architecture profile (`thumbv8m` in their target
12+
name).
13+
LLVM, the Rust compiler and the linker are providing
14+
[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the
15+
TrustZone-M feature.
16+
17+
One of the things provided, with this unstable feature, is the
18+
`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an
19+
entry function (see [section
20+
5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details).
21+
With this attribute, the compiler will do the following:
22+
* add a special symbol on the function which is the `__acle_se_` prefix and the
23+
standard function name
24+
* constrain the number of parameters to avoid using the Non-Secure stack
25+
* before returning from the function, clear registers that might contain Secure
26+
information
27+
* use the `BXNS` instruction to return
28+
29+
Because the stack can not be used to pass parameters, there will be compilation
30+
errors if:
31+
* the total size of all parameters is too big (for example more than four 32
32+
bits integers)
33+
* the entry function is not using a C ABI
34+
35+
The special symbol `__acle_se_` will be used by the linker to generate a secure
36+
gateway veneer.
37+
38+
<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
39+
40+
``` rust,ignore
41+
#![feature(cmse_nonsecure_entry)]
42+
43+
#[no_mangle]
44+
#[cmse_nonsecure_entry]
45+
pub extern "C" fn entry_function(input: u32) -> u32 {
46+
input + 6
47+
}
48+
```
49+
50+
``` text
51+
$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs
52+
$ arm-none-eabi-objdump -D function.o
53+
54+
00000000 <entry_function>:
55+
0: b580 push {r7, lr}
56+
2: 466f mov r7, sp
57+
4: b082 sub sp, #8
58+
6: 9001 str r0, [sp, #4]
59+
8: 1d81 adds r1, r0, #6
60+
a: 460a mov r2, r1
61+
c: 4281 cmp r1, r0
62+
e: 9200 str r2, [sp, #0]
63+
10: d30b bcc.n 2a <entry_function+0x2a>
64+
12: e7ff b.n 14 <entry_function+0x14>
65+
14: 9800 ldr r0, [sp, #0]
66+
16: b002 add sp, #8
67+
18: e8bd 4080 ldmia.w sp!, {r7, lr}
68+
1c: 4671 mov r1, lr
69+
1e: 4672 mov r2, lr
70+
20: 4673 mov r3, lr
71+
22: 46f4 mov ip, lr
72+
24: f38e 8800 msr CPSR_f, lr
73+
28: 4774 bxns lr
74+
2a: f240 0000 movw r0, #0
75+
2e: f2c0 0000 movt r0, #0
76+
32: f240 0200 movw r2, #0
77+
36: f2c0 0200 movt r2, #0
78+
3a: 211c movs r1, #28
79+
3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E>
80+
40: defe udf #254 ; 0xfe
81+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// gate-test-cmse_nonsecure_entry
2+
3+
#[no_mangle]
4+
#[cmse_nonsecure_entry]
5+
//~^ ERROR [E0775]
6+
//~| ERROR [E0658]
7+
pub extern "C" fn entry_function(input: u32) -> u32 {
8+
input + 6
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature
2+
--> $DIR/gate_test.rs:4:1
3+
|
4+
LL | #[cmse_nonsecure_entry]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #75835 <https://github.com/rust-lang/rust/issues/75835> for more information
8+
= help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable
9+
10+
error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension
11+
--> $DIR/gate_test.rs:4:1
12+
|
13+
LL | #[cmse_nonsecure_entry]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: aborting due to 2 previous errors
17+
18+
Some errors have detailed explanations: E0658, E0775.
19+
For more information about an error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// build-pass
2+
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
3+
// only-thumbv8m.main-none-eabi
4+
#![feature(cmse_nonsecure_entry)]
5+
#![no_std]
6+
7+
#[no_mangle]
8+
#[cmse_nonsecure_entry]
9+
pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 {
10+
a + b + c + d
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
// only-thumbv8m.main-none-eabi
3+
#![feature(cmse_nonsecure_entry)]
4+
#![no_std]
5+
6+
#[no_mangle]
7+
#[cmse_nonsecure_entry]
8+
pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { //~ ERROR
9+
a + b + c + d + e
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: <unknown>:0:0: in function entry_function i32 (i32, i32, i32, i32, i32): secure entry function requires arguments on stack
2+
3+
4+
error: aborting due to previous error
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// ignore-thumbv8m.main-none-eabi
2+
#![feature(cmse_nonsecure_entry)]
3+
4+
#[no_mangle]
5+
#[cmse_nonsecure_entry] //~ ERROR [E0775]
6+
pub extern "C" fn entry_function(input: u32) -> u32 {
7+
input + 6
8+
}
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension
2+
--> $DIR/trustzone-only.rs:5:1
3+
|
4+
LL | #[cmse_nonsecure_entry]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0775`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
// only-thumbv8m.main-none-eabi
3+
#![feature(cmse_nonsecure_entry)]
4+
#![no_std]
5+
6+
#[no_mangle]
7+
#[cmse_nonsecure_entry]
8+
pub fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { //~ ERROR [E0776]
9+
a + b + c + d
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0776]: `#[cmse_nonsecure_entry]` functions require C ABI
2+
--> $DIR/wrong-abi.rs:7:1
3+
|
4+
LL | #[cmse_nonsecure_entry]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0776`.

0 commit comments

Comments
 (0)