-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a new ABI to support cmse_nonsecure_call #81346
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
The job Click to see the possible cause of the failure (guessed by this bot)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, please create a new tracking issue for this ABI
#[no_mangle] | ||
pub fn test(a: u32, b: u32, c: u32, d: u32) -> u32 { | ||
let non_secure_function = unsafe { | ||
core::mem::transmute::<usize, extern "cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add a test that defines a extern "cmse-nonsecure-call" fn
in Rust instead of transmuting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried the following (if that is what you meant):
#![no_std]
#![feature(abi_cmse_nonsecure_call)]
#[no_mangle]
pub fn test() -> u32 {
toto()
}
extern "cmse-nonsecure-call" fn toto() -> u32 {
45
}
and I have the following LLVM error:
[hugdev01@machine tests]$ rustc +stage1 --target thumbv8m.main-none-eabi --crate-type lib --emit asm toto.rs
rustc: /home/hugdev01/dev/rust-work/rust/src/llvm-project/llvm/lib/Target/ARM/ARMISelLowering.cpp:2556: virtual llvm::SDValue llvm::ARMTargetLowering::LowerCall(llvm::TargetLowering::CallLoweringInfo&, llvm::SmallVectorImpl<llvm::SDValue>&) const: Assertion `!isARMFunc && !isDirect && "Cannot handle call to ARM function or direct call"' failed.
Aborted (core dumped)
I believe this is because it is forbidden, in LLVM this callsite attribute can really only be used on function pointers but not directly on function declaration.
The specification document says that section 5.5:
A non-secure function type must only be used as a base type of a pointer. This disallows function definitions with this attribute and ensures a secure executable file only contains secure function definitions.
I guess ideally this kind of error should be returned by Rust instead of LLVM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. So the intention is that secure and non-secure worlds are always entirely separate executables, and cmse-nonsecure-call
is used by the secure side only to invoke callback functions passed by the non-secure side?
Where can I find documentation of the LLVM implementation? https://llvm.org/docs/LangRef.html doesn't mention it.
(I agree that this should be checked by rustc instead of LLVM, especially since this is not a diagnostic but an assertion failure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the intention is that secure and non-secure worlds are always entirely separate executables
Yes true!
cmse-nonsecure-call is used by the secure side only to invoke callback functions passed by the non-secure side?
Yes I believe that is the main use-case! It's also possible for the Secure side to call functions that it knows are at particular addresses, for example the non-secure reset handler.
Where can I find documentation of the LLVM implementation? https://llvm.org/docs/LangRef.html doesn't mention it.
There isn't much documentation of how those features are implemented in LLVM 😅. The changes were introduced by this mail on the mailing list a long time ago. Apart from that there are the specifications and the various commits on LLVM to get an idea of how it's implemented. Not ideal, I know.
(I agree that this should be checked by rustc instead of LLVM, especially since this is not a diagnostic but an assertion failure)
I am going to look where it is possible to check the position of the extern
keywork to differentiate between function declaration/definition and function pointer type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a way to do this in the AST visitor it seems, by checking if the ABI is applied on a bare function or not. Might be a bit hacky to modify function prototype just for this feature. But it works!
|
||
if self.conv == Conv::CmseNonSecureCall { | ||
// This will probably get ignored on all targets but those supporting the TrustZone-M | ||
// extension (thumbv8m targets). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should reject the ABI when using a --target
that doesn't support it (hmm, do we not do that for #[cmse_non_secure_entry]
?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True! Initially I was looking how to check the target from this file but I am not sure how to get the target information from there. It looks like it would be possible to do it in the change file compiler/rustc_ast_passes/src/feature_gate.rs
as there is access to the rustc_session::session::Session
structure which contains the target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do, can I maybe re-use and modify the same error code used for cmse_nonsecure_entry
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that should be fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feature_gate.rs
is not the right place to check this though. We already have per-target lists of supported ABIs, this should just plug in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, sorry I mixed up the two things and thought we were talking about the target check. Cool I can move the bare_function
check there.
Just wondering how I would do it 😅 In the feature_gate.rs
I can have the information that the compiler is currently checking a bare function type but I don't see how I can check that in the check.rs
file. Or did you mean that I should call the check_abi
function of check.rs
(with the bare_function
info) from the feature_gate.rs
file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, feature_gate.rs
should not be involved in checking ABI-specific restrictions. I'm not sure where the best way to put this is, perhaps you have to write your own visitor, similar to what inline asm uses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, got it.
I noticed that check_abi
on check.rs
is only called to check the ABI of function declarations and external blocks which are the exact two cases where the CCmseNonSecureCall
ABI is forbidden. I believe the other only use of extern
is for function pointer and that one is allowed.
So one easy way would be to add a check for CCmseNonSecureCall
inside check_abi
and emit an error if that's equal. I tested it and it works as expected.
Maybe it's a bit risky if check_abi
is ever used for function pointers but we can add tests covering all the cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, seems fine if there are tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok done, there should be:
- one test checking that the ABI on a function pointer compiles successfully
- one test checking that the ABI on on function definition fails
- one test checking that the ABI on an external block fails
ac2bb2e
to
ab06dbc
Compare
The job Click to see the possible cause of the failure (guessed by this bot)
|
Shall I then group both CMSE features UI tests in the same subdirectory (for the attribute and the ABI)? |
Yes, that seems good |
ab06dbc
to
e18357d
Compare
I put a C in front of everything as mentionned in the tracking issue as well. |
e18357d
to
b56857f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Just one minor nit, then this should be good to go.
@@ -0,0 +1,9 @@ | |||
error[E0781]: The `"cmse-nonsecure-call"` ABI is only allowed on function pointers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this not fail in CI? The message should now be lowercased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the feeling that the tests with:
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
// only-thumbv8m.main-none-eabi
are ignored on CI 😕
edit: updated the stderr
files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right. They are skipped by the PR builder, but the "real" CI should check them.
ad68223
to
4aae28d
Compare
Let's give this a shot @bors r+ rollup=iffy |
📌 Commit 4aae28da042dcc0053f36b83c65061798f4d497e has been approved by |
⌛ Testing commit 4aae28da042dcc0053f36b83c65061798f4d497e with merge 489d779e45bf34f3daea611ef1f14518444b9daf... |
The job Click to see the possible cause of the failure (guessed by this bot)
|
💔 Test failed - checks-actions |
This commit adds a new ABI to be selected via `extern "C-cmse-nonsecure-call"` on function pointers in order for the compiler to apply the corresponding cmse_nonsecure_call callsite attribute. For Armv8-M targets supporting TrustZone-M, this will perform a non-secure function call by saving, clearing and calling a non-secure function pointer using the BLXNS instruction. See the page on the unstable book for details. Signed-off-by: Hugues de Valon <hugues.devalon@arm.com>
4aae28d
to
ce9818f
Compare
@@ -28,6 +28,7 @@ fn clif_sig_from_fn_abi<'tcx>( | |||
Conv::X86_64SysV => CallConv::SystemV, | |||
Conv::X86_64Win64 => CallConv::WindowsFastcall, | |||
Conv::ArmAapcs | |||
| Conv::CCmseNonSecureCall |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebased and added this to fix the error
@bors r+ |
📌 Commit ce9818f has been approved by |
☀️ Test successful - checks-actions |
This adds support for the
cmse_nonsecure_call
feature to be able to perform non-secure function call.See the discussion on Zulip here.
This is a followup to #75810 which added
cmse_nonsecure_entry
. As for that PR, I assume that the changes are small enough to not have to go through a RFC but I don't mind doing one if needed 😃I did not yet create a tracking issue, but if most of it is fine, I can create one and update the various files accordingly (they refer to the other tracking issue now).
On the Zulip chat, I believe @jonas-schievink volunteered to be a reviewer 💯