diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 227a87ff81994..73c34818446a6 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/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 937821e9d4fb2..f35c1016f86be 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -344,6 +344,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void .expect("non-UTF8 diagnostic"); diag_handler.warn(&msg); } + llvm::diagnostic::Unsupported(diagnostic_ref) => { + let msg = llvm::build_string(|s| { + llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) + }) + .expect("non-UTF8 diagnostic"); + diag_handler.err(&msg); + } llvm::diagnostic::UnknownDiagnostic(..) => {} } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 47f5c94e70c53..ccd3e42e458fd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -118,6 +118,7 @@ pub enum Diagnostic<'ll> { InlineAsm(InlineAsmDiagnostic<'ll>), PGO(&'ll DiagnosticInfo), Linker(&'ll DiagnosticInfo), + Unsupported(&'ll DiagnosticInfo), /// LLVM has other types that we do not wrap here. UnknownDiagnostic(&'ll DiagnosticInfo), @@ -159,6 +160,7 @@ impl Diagnostic<'ll> { Dk::PGOProfile => PGO(di), Dk::Linker => Linker(di), + Dk::Unsupported => Unsupported(di), _ => UnknownDiagnostic(di), } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 45c5f56f44793..af3f3e7aa03c0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -483,6 +483,7 @@ pub enum DiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, } /// LLVMRustDiagnosticLevel diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index c09e3659f80a2..ed9b99188bb90 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 a202736ea6cbe..8b21dacf78724 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -458,6 +458,8 @@ 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"), +E0776: include_str!("./error_codes/E0776.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 0000000000000..9bafd52f75cf2 --- /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] +pub extern "C" fn entry_function() {} +``` + +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_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md new file mode 100644 index 0000000000000..d65beebe07c61 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -0,0 +1,13 @@ +`#[cmse_nonsecure_entry]` functions require a C ABI + +Erroneous code example: + +```compile_fail,E0776 +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub fn entry_function(input: Vec) {} +``` + +To fix this error, declare your entry function with a C ABI, using `extern "C"`. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7f5b19134804e..348cff8d2dad2 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 22c1ca2f289d3..b7e113e601007 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_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e85a9b7638004..9f8ea7f43d84b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1171,6 +1171,7 @@ enum class LLVMRustDiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, }; static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { @@ -1197,6 +1198,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { return LLVMRustDiagnosticKind::PGOProfile; case DK_Linker: return LLVMRustDiagnosticKind::Linker; + case DK_Unsupported: + return LLVMRustDiagnosticKind::Unsupported; default: return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 62a6198b9b402..d71cdc4e67de4 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 4234aef335906..e3ad31469b237 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 d6985f3bd4d63..9aca112a9142d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2543,6 +2543,21 @@ 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.fn_sig(id).abi() != abi::Abi::C { + struct_span_err!( + tcx.sess, + attr.span, + E0776, + "`#[cmse_nonsecure_entry]` requires C ABI" + ) + .emit(); + } + 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 0000000000000..338fbc4b2bfca --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -0,0 +1,81 @@ +# `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 + +Because the stack can not be used to pass parameters, there will be compilation +errors if: +* the total size of all parameters is too big (for example more than four 32 + bits integers) +* the entry function is not using a C ABI + +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 7075196da1aa3..2c56ba7db75b5 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/gate_test.rs b/src/test/ui/cmse-nonsecure-entry/gate_test.rs new file mode 100644 index 0000000000000..02d5f20febc4a --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.rs @@ -0,0 +1,11 @@ +// gate-test-cmse_nonsecure_entry + +#[no_mangle] +#[cmse_nonsecure_entry] +//~^ ERROR [E0775] +//~| ERROR [E0658] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.stderr b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr new file mode 100644 index 0000000000000..75a29b317df87 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr @@ -0,0 +1,19 @@ +error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #75835 for more information + = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable + +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0775. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs new file mode 100644 index 0000000000000..a723eb734731d --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs @@ -0,0 +1,11 @@ +// build-pass +// 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) -> u32 { + a + b + c + d +} 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 0000000000000..553d3a8cb0be7 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs @@ -0,0 +1,10 @@ +// 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 { //~ ERROR + 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 0000000000000..d9956acbe7577 --- /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 0000000000000..3783e2794021f --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs @@ -0,0 +1,10 @@ +// 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 0000000000000..7e8862f9ab7f2 --- /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:5:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0775`. diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs new file mode 100644 index 0000000000000..611c8643dcb02 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs @@ -0,0 +1,10 @@ +// 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 fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { //~ ERROR [E0776] + a + b + c + d +} diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr new file mode 100644 index 0000000000000..d6967a11e6bf7 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr @@ -0,0 +1,9 @@ +error[E0776]: `#[cmse_nonsecure_entry]` functions require C ABI + --> $DIR/wrong-abi.rs:7:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0776`.