From 1aaafac6ffec2556a27a3c34365c685c124ee029 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Mon, 28 Sep 2020 21:10:38 +0100 Subject: [PATCH] Add support for cmse_nonsecure_entry attribute This patch adds support for the LLVM cmse_nonsecure_entry attribute. This is a target-dependent attribute that only has sense for the thumbv8m Rust targets. You can find more information about this attribute here: https://developer.arm.com/documentation/ecm0359818/latest/ Signed-off-by: Hugues de Valon --- compiler/rustc_codegen_llvm/src/attributes.rs | 3 + compiler/rustc_codegen_llvm/src/llvm/mod.rs | 6 ++ compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0775.md | 17 +++++ compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_feature/src/builtin_attrs.rs | 2 + .../src/middle/codegen_fn_attrs.rs | 3 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/collect.rs | 6 ++ .../language-features/cmse-nonsecure-entry.md | 75 +++++++++++++++++++ src/llvm-project | 2 +- .../cmse-nonsecure-entry/params-on-stack.rs | 11 +++ .../params-on-stack.stderr | 5 ++ .../ui/cmse-nonsecure-entry/trustzone-only.rs | 11 +++ .../trustzone-only.stderr | 9 +++ 15 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0775.md create mode 100644 src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md create mode 100644 src/test/ui/cmse-nonsecure-entry/params-on-stack.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr create mode 100644 src/test/ui/cmse-nonsecure-entry/trustzone-only.rs create mode 100644 src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 227a87ff819..73c34818446 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -294,6 +294,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { + llvm::AddFunctionAttrString(llfn, Function, const_cstr!("cmse_nonsecure_entry")); + } sanitize(cx, codegen_fn_attrs.no_sanitize, llfn); // Always annotate functions with the target-cpu they are compiled for. diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index c09e3659f80..ed9b99188bb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -37,6 +37,12 @@ pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &C } } +pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) { + unsafe { + LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null()) + } +} + #[derive(Copy, Clone)] pub enum AttributePlace { ReturnValue, diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index a202736ea6c..c9753296732 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -458,6 +458,7 @@ E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), E0773: include_str!("./error_codes/E0773.md"), E0774: include_str!("./error_codes/E0774.md"), +E0775: include_str!("./error_codes/E0775.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md new file mode 100644 index 00000000000..f21ee73791c --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -0,0 +1,17 @@ +`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M +extension. + +Erroneous code example: + +```compile_fail,E0775 +#![feature(cmse_nonsecure_entry)] + +#[cmse_nonsecure_entry] +fn toto() {} +``` + +To fix this error, compile your code for a Rust target that supports the +TrustZone-M extension. The current possible targets are: +* `thumbv8m.main-none-eabi` +* `thumbv8m.main-none-eabihf` +* `thumbv8m.base-none-eabi` diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7f5b1913480..348cff8d2da 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -590,6 +590,9 @@ declare_features! ( /// Allows using and casting function pointers in a `const fn`. (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None), + /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 22c1ca2f289..b7e113e6010 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -349,6 +349,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(register_tool), ), + gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 62a6198b9b4..d71cdc4e67d 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -79,6 +79,9 @@ bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 13; + /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a + /// function as an entry function from Non-Secure code. + const CMSE_NONSECURE_ENTRY = 1 << 14; } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4234aef3359..e3ad31469b2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -337,6 +337,7 @@ symbols! { closure_to_fn_coercion, cmp, cmpxchg16b_target_feature, + cmse_nonsecure_entry, coerce_unsized, cold, column, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d6985f3bd4d..6c0d51ed717 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2543,6 +2543,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if tcx.sess.check_name(attr, sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) { + if !tcx.sess.target.target.llvm_target.contains("thumbv8m") { + struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; } else if tcx.sess.check_name(attr, sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if tcx.sess.check_name(attr, sym::track_caller) { diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md new file mode 100644 index 00000000000..9d69be3e69b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -0,0 +1,75 @@ +# `cmse_nonsecure_entry` + +The tracking issue for this feature is: [#75835] + +[#75835]: https://github.com/rust-lang/rust/issues/75835 + +------------------------ + +The [TrustZone-M +feature](https://developer.arm.com/documentation/100690/latest/) 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](https://developer.arm.com/documentation/ecm0359818/latest/) for the +TrustZone-M feature. + +One of the things provided, with this unstable feature, is the +`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an +entry function (see [section +5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). +With this attribute, the compiler will do the following: +* add a special symbol on the function which is the `__acle_se_` prefix and the + standard function name +* constrain the number of parameters to avoid using the Non-Secure stack +* before returning from the function, clear registers that might contain Secure + information +* use the `BXNS` instruction to return + +The special symbol `__acle_se_` will be used by the linker to generate a secure +gateway veneer. + + + +``` rust,ignore +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} +``` + +``` text +$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs +$ arm-none-eabi-objdump -D function.o + +00000000 : + 0: b580 push {r7, lr} + 2: 466f mov r7, sp + 4: b082 sub sp, #8 + 6: 9001 str r0, [sp, #4] + 8: 1d81 adds r1, r0, #6 + a: 460a mov r2, r1 + c: 4281 cmp r1, r0 + e: 9200 str r2, [sp, #0] + 10: d30b bcc.n 2a + 12: e7ff b.n 14 + 14: 9800 ldr r0, [sp, #0] + 16: b002 add sp, #8 + 18: e8bd 4080 ldmia.w sp!, {r7, lr} + 1c: 4671 mov r1, lr + 1e: 4672 mov r2, lr + 20: 4673 mov r3, lr + 22: 46f4 mov ip, lr + 24: f38e 8800 msr CPSR_f, lr + 28: 4774 bxns lr + 2a: f240 0000 movw r0, #0 + 2e: f2c0 0000 movt r0, #0 + 32: f240 0200 movw r2, #0 + 36: f2c0 0200 movt r2, #0 + 3a: 211c movs r1, #28 + 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E> + 40: defe udf #254 ; 0xfe +``` diff --git a/src/llvm-project b/src/llvm-project index 7075196da1a..2c56ba7db75 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 7075196da1aa3527f7c87943607e25f3cf24997a +Subproject commit 2c56ba7db75b536b0432228b4760ed79174eca30 diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs new file mode 100644 index 00000000000..14c334fd010 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs @@ -0,0 +1,11 @@ +// gate-test-cmse_nonsecure_entry +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { + a + b + c + d + e +} diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr new file mode 100644 index 00000000000..d9956acbe75 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr @@ -0,0 +1,5 @@ +error: :0:0: in function entry_function i32 (i32, i32, i32, i32, i32): secure entry function requires arguments on stack + + +error: aborting due to previous error + diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs new file mode 100644 index 00000000000..efb4eb09b68 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs @@ -0,0 +1,11 @@ +// gate-test-cmse_nonsecure_entry +// ignore-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] //~ ERROR [E0775] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr new file mode 100644 index 00000000000..d3e0c1e42eb --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr @@ -0,0 +1,9 @@ +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/trustzone-only.rs:6:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0775`.