Skip to content
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

Merged
merged 1 commit into from
Feb 3, 2021

Conversation

hug-dev
Copy link
Contributor

@hug-dev hug-dev commented Jan 24, 2021

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 💯

@rust-highfive
Copy link
Collaborator

r? @GuillaumeGomez

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 24, 2021
@rust-log-analyzer
Copy link
Collaborator

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.channel         := nightly
configure: rust.debug-assertions := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 
---
   Compiling regex v1.4.3
   Compiling tidy v0.1.0 (/checkout/src/tools/tidy)
    Finished release [optimized] target(s) in 10.11s
tidy check
tidy error: following path contains more than 1458 entries, you should move the test to some relevant subdirectory (current: 1459): /checkout/src/test/ui
Found 435 error codes
Found 0 error codes with no tests
Done!
some tidy checks failed

Copy link
Contributor

@jonas-schievink jonas-schievink left a 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>(
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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)

Copy link
Contributor Author

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.

Copy link
Contributor Author

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).
Copy link
Contributor

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]?)

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor Author

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

@camelid
Copy link
Member

camelid commented Jan 24, 2021

r? @jonas-schievink

@rust-log-analyzer
Copy link
Collaborator

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.channel         := nightly
configure: rust.debug-assertions := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 
---
   Compiling regex v1.4.3
   Compiling tidy v0.1.0 (/checkout/src/tools/tidy)
    Finished release [optimized] target(s) in 9.62s
tidy check
tidy error: following path contains more than 1458 entries, you should move the test to some relevant subdirectory (current: 1459): /checkout/src/test/ui
Found 436 error codes
Found 0 error codes with no tests
Done!
some tidy checks failed

@hug-dev
Copy link
Contributor Author

hug-dev commented Jan 26, 2021

tidy error: following path contains more than 1458 entries, you should move the test to some relevant subdirectory (current: 1459): /checkout/src/test/ui

Shall I then group both CMSE features UI tests in the same subdirectory (for the attribute and the ABI)?

@jonas-schievink
Copy link
Contributor

Shall I then group both CMSE features UI tests in the same subdirectory (for the attribute and the ABI)?

Yes, that seems good

@hug-dev hug-dev force-pushed the nonsecure-call-abi branch from ab06dbc to e18357d Compare January 27, 2021 18:12
@hug-dev
Copy link
Contributor Author

hug-dev commented Jan 27, 2021

I put a C in front of everything as mentionned in the tracking issue as well.

@hug-dev hug-dev force-pushed the nonsecure-call-abi branch from e18357d to b56857f Compare January 30, 2021 14:48
Copy link
Contributor

@jonas-schievink jonas-schievink left a 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.

compiler/rustc_typeck/src/check/check.rs Outdated Show resolved Hide resolved
@@ -0,0 +1,9 @@
error[E0781]: The `"cmse-nonsecure-call"` ABI is only allowed on function pointers.
Copy link
Contributor

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.

Copy link
Contributor Author

@hug-dev hug-dev Feb 1, 2021

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

Copy link
Contributor

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.

@hug-dev hug-dev force-pushed the nonsecure-call-abi branch from ad68223 to 4aae28d Compare February 1, 2021 14:52
@jonas-schievink
Copy link
Contributor

Let's give this a shot

@bors r+ rollup=iffy

@bors
Copy link
Contributor

bors commented Feb 1, 2021

📌 Commit 4aae28da042dcc0053f36b83c65061798f4d497e has been approved by jonas-schievink

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 1, 2021
@bors
Copy link
Contributor

bors commented Feb 1, 2021

⌛ Testing commit 4aae28da042dcc0053f36b83c65061798f4d497e with merge 489d779e45bf34f3daea611ef1f14518444b9daf...

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-debug failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
    Checking cranelift-frontend v0.69.0 (https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768)
    Checking cranelift-jit v0.69.0 (https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768)
    Checking cranelift-object v0.69.0 (https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768)
    Checking rustc_codegen_cranelift v0.1.0 (/checkout/compiler/rustc_codegen_cranelift)
error[E0004]: non-exhaustive patterns: `CCmseNonSecureCall` not covered
   --> src/abi/mod.rs:26:27
    |
26  |     let call_conv = match fn_abi.conv {
    |                           ^^^^^^^^^^^ pattern `CCmseNonSecureCall` not covered
   ::: /checkout/compiler/rustc_target/src/abi/call/mod.rs:554:5
    |
    |
554 |     CCmseNonSecureCall,
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `Conv`

@bors
Copy link
Contributor

bors commented Feb 1, 2021

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Feb 1, 2021
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>
@hug-dev hug-dev force-pushed the nonsecure-call-abi branch from 4aae28d to ce9818f Compare February 2, 2021 13:07
@@ -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
Copy link
Contributor Author

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

@jonas-schievink
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Feb 2, 2021

📌 Commit ce9818f has been approved by jonas-schievink

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 2, 2021
@bors
Copy link
Contributor

bors commented Feb 3, 2021

⌛ Testing commit ce9818f with merge b593389...

@bors
Copy link
Contributor

bors commented Feb 3, 2021

☀️ Test successful - checks-actions
Approved by: jonas-schievink
Pushing b593389 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 3, 2021
@bors bors merged commit b593389 into rust-lang:master Feb 3, 2021
@rustbot rustbot added this to the 1.51.0 milestone Feb 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants