"efiapi ABI is experimental and subject to change"
);
}
+ "C-cmse-nonsecure-call" => {
+ gate_feature_post!(
+ &self,
+ abi_c_cmse_nonsecure_call,
+ span,
+ "C-cmse-nonsecure-call ABI is experimental and subject to change"
+ );
+ }
abi => self
.sess
.parse_sess
Conv::X86_64SysV => CallConv::SystemV,
Conv::X86_64Win64 => CallConv::WindowsFastcall,
Conv::ArmAapcs
+ | Conv::CCmseNonSecureCall
| Conv::Msp430Intr
| Conv::PtxKernel
| Conv::X86Fastcall
fn llvm_cconv(&self) -> llvm::CallConv {
match self.conv {
- Conv::C | Conv::Rust => llvm::CCallConv,
+ Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
if cconv != llvm::CCallConv {
llvm::SetInstructionCallConv(callsite, cconv);
}
+
+ if self.conv == Conv::CCmseNonSecureCall {
+ // This will probably get ignored on all targets but those supporting the TrustZone-M
+ // extension (thumbv8m targets).
+ unsafe {
+ llvm::AddCallSiteAttrString(
+ callsite,
+ llvm::AttributePlace::Function,
+ rustc_data_structures::const_cstr!("cmse_nonsecure_call"),
+ );
+ }
+ }
}
}
// Operations on call sites
pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint);
pub fn LLVMRustAddCallSiteAttribute(Instr: &Value, index: c_uint, attr: Attribute);
+ pub fn LLVMRustAddCallSiteAttrString(Instr: &Value, index: c_uint, Name: *const c_char);
pub fn LLVMRustAddAlignmentCallSiteAttr(Instr: &Value, index: c_uint, bytes: u32);
pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: &Value, index: c_uint, bytes: u64);
pub fn LLVMRustAddDereferenceableOrNullCallSiteAttr(Instr: &Value, index: c_uint, bytes: u64);
}
}
+pub fn AddCallSiteAttrString(callsite: &Value, idx: AttributePlace, attr: &CStr) {
+ unsafe { LLVMRustAddCallSiteAttrString(callsite, idx.as_uint(), attr.as_ptr()) }
+}
+
#[derive(Copy, Clone)]
pub enum AttributePlace {
ReturnValue,
E0778: include_str!("./error_codes/E0778.md"),
E0779: include_str!("./error_codes/E0779.md"),
E0780: include_str!("./error_codes/E0780.md"),
+E0781: include_str!("./error_codes/E0781.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
--- /dev/null
+The `C-cmse-nonsecure-call` ABI can only be used with function pointers.
+
+Erroneous code example:
+
+```compile_fail,E0781
+#![feature(abi_c_cmse_nonsecure_call)]
+
+pub extern "C-cmse-nonsecure-call" fn test() {}
+```
+
+The `C-cmse-nonsecure-call` ABI should be used by casting function pointers to
+specific addresses.
/// Allows using `pointer` and `reference` in intra-doc links
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
+
+ /// Allows `extern "C-cmse-nonsecure-call" fn()`.
+ (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Call->addAttribute(Index, Attr);
}
+extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index,
+ const char *Name) {
+ CallBase *Call = unwrap<CallBase>(Instr);
+ Attribute Attr = Attribute::get(Call->getContext(), Name);
+ Call->addAttribute(Index, Attr);
+}
+
+
extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint32_t Bytes) {
Win64 => Conv::X86_64Win64,
SysV64 => Conv::X86_64SysV,
Aapcs => Conv::ArmAapcs,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
PtxKernel => Conv::PtxKernel,
Msp430Interrupt => Conv::Msp430Intr,
X86Interrupt => Conv::X86Intr,
abi,
abi_amdgpu_kernel,
abi_avr_interrupt,
+ abi_c_cmse_nonsecure_call,
abi_efiapi,
abi_msp430_interrupt,
abi_ptx,
// Target-specific calling conventions.
ArmAapcs,
+ CCmseNonSecureCall,
Msp430Intr,
EfiApi,
AvrInterrupt,
AvrNonBlockingInterrupt,
+ CCmseNonSecureCall,
// Multiplatform / generic ABIs
System,
name: "avr-non-blocking-interrupt",
generic: false,
},
+ AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
// Cross-platform ABIs
AbiData { abi: Abi::System, name: "system", generic: true },
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
)
.emit()
}
+
+ // This ABI is only allowed on function pointers
+ if abi == Abi::CCmseNonSecureCall {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0781,
+ "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers."
+ )
+ .emit()
+ }
}
/// Helper used for fns and closures. Does the grungy work of checking a function
--- /dev/null
+# `abi_c_cmse_nonsecure_call`
+
+The tracking issue for this feature is: [#81391]
+
+[#81391]: https://github.com/rust-lang/rust/issues/81391
+
+------------------------
+
+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
+`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](https://developer.arm.com/documentation/ecm0359818/latest/) 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.
+
+<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
+
+``` rust,ignore
+#![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()
+}
+```
+
+``` text
+$ 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}
+```
+++ /dev/null
-// 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() {}
+++ /dev/null
-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 <https://github.com/rust-lang/rust/issues/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`.
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-error: <unknown>: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
-
+++ /dev/null
-// 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() {}
+++ /dev/null
-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`.
+++ /dev/null
-// 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
-}
+++ /dev/null
-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`.
--- /dev/null
+// gate-test-abi_c_cmse_nonsecure_call
+fn main() {
+ let non_secure_function = unsafe {
+ core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
+ //~^ ERROR [E0658]
+ 0x10000004,
+ )
+ };
+ let mut toto = 5;
+ toto += non_secure_function(toto, 2, 3, 5);
+}
--- /dev/null
+error[E0658]: C-cmse-nonsecure-call ABI is experimental and subject to change
+ --> $DIR/gate_test.rs:4:46
+ |
+LL | core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #81391 <https://github.com/rust-lang/rust/issues/81391> for more information
+ = help: add `#![feature(abi_c_cmse_nonsecure_call)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// build-pass
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(abi_c_cmse_nonsecure_call)]
+#![no_std]
+
+#[no_mangle]
+pub fn test(a: u32, b: u32, c: u32, d: u32) -> u32 {
+ let non_secure_function = unsafe {
+ core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32>(
+ 0x10000004,
+ )
+ };
+ non_secure_function(a, b, c, d)
+}
--- /dev/null
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(abi_c_cmse_nonsecure_call)]
+#![no_std]
+
+#[no_mangle]
+pub fn test(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 {
+ let non_secure_function = unsafe {
+ core::mem::transmute::<
+ usize,
+ extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32>
+ (
+ 0x10000004,
+ )
+ };
+ non_secure_function(a, b, c, d, e)
+}
--- /dev/null
+error: <unknown>:0:0: in function test i32 (i32, i32, i32, i32, i32): call to non-secure function would require passing arguments on stack
+
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(abi_c_cmse_nonsecure_call)]
+#![no_std]
+
+pub extern "C-cmse-nonsecure-call" fn test() {} //~ ERROR [E0781]
--- /dev/null
+error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers.
+ --> $DIR/wrong-abi-location-1.rs:6:1
+ |
+LL | pub extern "C-cmse-nonsecure-call" fn test() {} //~ ERROR [E0781]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0781`.
--- /dev/null
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(abi_c_cmse_nonsecure_call)]
+#![no_std]
+
+extern "C-cmse-nonsecure-call" { //~ ERROR [E0781]
+ fn test();
+}
--- /dev/null
+error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers.
+ --> $DIR/wrong-abi-location-2.rs:6:1
+ |
+LL | / extern "C-cmse-nonsecure-call" {
+LL | | fn test(); //~ ERROR [E0781]
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0781`.
--- /dev/null
+// 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() {}
--- /dev/null
+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 <https://github.com/rust-lang/rust/issues/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`.
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+error: <unknown>: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
+
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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
+}
--- /dev/null
+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`.
LL | extern "路濫狼á́́" fn foo() {}
| ^^^^^^^^^ invalid ABI
|
- = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+ = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
error: aborting due to previous error
LL | "invalid-ab_isize"
| ^^^^^^^^^^^^^^^^^^ invalid ABI
|
- = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+ = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
error: aborting due to previous error