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

Experimental tracepoint support #1084

Open
wants to merge 3 commits into
base: rust-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rust: add static_key_false
Add just enough support for static key so that we can use it from
tracepoints. Tracepoints rely on `static_key_false` even though it is
deprecated, so we add the same functionality to Rust.

Signed-off-by: Alice Ryhl <[email protected]>
  • Loading branch information
Darksonn committed Jun 6, 2024
commit 38720c0449960c6dd027b1a5084db31fac34e55f
1 change: 1 addition & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod prelude;
pub mod print;
mod static_assert;
pub mod static_call;
pub mod static_key;
#[doc(hidden)]
pub mod std_vendor;
pub mod str;
Expand Down
150 changes: 150 additions & 0 deletions rust/kernel/static_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0
Darksonn marked this conversation as resolved.
Show resolved Hide resolved

// Copyright (C) 2024 Google LLC.

//! Logic for static keys.

use crate::bindings::*;

#[doc(hidden)]
#[macro_export]
#[cfg(target_arch = "x86_64")]
#[cfg(not(CONFIG_HAVE_RUST_ASM_GOTO))]
macro_rules! _static_key_false {
($key:path, $keytyp:ty, $field:ident) => {{
let mut output = 1u32;

core::arch::asm!(
r#"
1: .byte 0x0f,0x1f,0x44,0x00,0x00

.pushsection __jump_table, "aw"
.balign 8
.long 1b - .
.long 3f - .
.quad {0} + {1} - .
.popsection

2: mov {2:e}, 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may want to use att_syntax ;-)

Copy link
Collaborator Author

@Darksonn Darksonn May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you show me how to do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options(att_syntax), here is an example:

unsafe fn i32_xadd(v: *mut i32, mut i: i32) -> i32 {
    // SAFETY: Per function safety requirement, the address of `v` is valid for "xadd".
    unsafe {
        asm!(
            lock_instr!("xaddl {i:e}, ({v})"),
            i = inout(reg) i,
            v = in(reg) v,
            options(att_syntax, preserves_flags),
        );
    }

    i
}

in https://lore.kernel.org/rust-for-linux/[email protected]/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kernel developers will prefer that, yeah... :)

Sadly, specifying every single time that may be painful. Perhaps we could have our own asm! that expands to the actual one plus that option, if that is possible, or otherwise it would be nice to have a rustc flag to always use that by default.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to our wishlist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A asm! wrapper should be fairly straightforward. The asm macro deliberately allows multiple options to simplify cases where people want to always add options(att_syntax). See rust-lang/rust#73227.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Gary, then we should probably do it soon if we are going to start adding more asm! blocks. I would still like to have a flag (or similar) nevertheless, to avoid extra macros and to match the C compilers.

3:
"#,
sym $key,
const ::core::mem::offset_of!($keytyp, $field),
Darksonn marked this conversation as resolved.
Show resolved Hide resolved
inout(reg) output,
);

output != 0
}};
}

#[doc(hidden)]
#[macro_export]
#[cfg(target_arch = "x86_64")]
#[cfg(CONFIG_HAVE_RUST_ASM_GOTO)]
macro_rules! _static_key_false {
($key:path, $keytyp:ty, $field:ident) => {'my_label: {
core::arch::asm!(
r#"
1: .byte 0x0f,0x1f,0x44,0x00,0x00

.pushsection __jump_table, "aw"
.balign 8
.long 1b - .
.long {0} - .
.quad {1} + {2} - .
.popsection
"#,
label {
break 'my_label true;
},
sym $key,
const ::core::mem::offset_of!($keytyp, $field),
);

break 'my_label false;
}};
}

#[doc(hidden)]
#[macro_export]
#[cfg(target_arch = "aarch64")]
#[cfg(not(CONFIG_HAVE_RUST_ASM_GOTO))]
macro_rules! _static_key_false {
($key:path, $keytyp:ty, $field:ident) => {{
let mut output = 1u32;

core::arch::asm!(
r#"
1: nop

.pushsection __jump_table, "aw"
.align 3
.long 1b - ., 3f - .
.quad {0} + {1} - .
.popsection

2: mov {2:w}, 0
3:
"#,
sym $key,
const ::core::mem::offset_of!($keytyp, $field),
inout(reg) output
);

output != 0
}};
}

#[doc(hidden)]
#[macro_export]
#[cfg(target_arch = "aarch64")]
#[cfg(CONFIG_HAVE_RUST_ASM_GOTO)]
macro_rules! _static_key_false {
($key:path, $keytyp:ty, $field:ident) => {'my_label: {
core::arch::asm!(
r#"
1: nop

.pushsection __jump_table, "aw"
.align 3
.long 1b - ., {0} - .
.quad {1} + {2} - .
.popsection
"#,
label {
break 'my_label true;
},
sym $key,
const ::core::mem::offset_of!($keytyp, $field),
);

break 'my_label false;
}};
}

/// Branch based on a static key.
///
/// Takes three arguments:
///
/// * `key` - the path to the static variable containing the `static_key`.
/// * `keytyp` - the type of `key`.
/// * `field` - the name of the field of `key` that contains the `static_key`.
#[macro_export]
macro_rules! static_key_false {
// Forward to the real implementation. Separated like this so that we don't have to duplicate
// the documentation.
($key:path, $keytyp:ty, $field:ident) => {{
// Assert that `$key` has type `$keytyp` and that `$key.$field` has type `static_key`.
//
// SAFETY: We know that `$key` is a static because otherwise the inline assembly will not
// compile. The raw pointers created in this block are in-bounds of `$key`.
static _TY_ASSERT: () = unsafe {
let key: *const $keytyp = ::core::ptr::addr_of!($key);
let _: *const $crate::bindings::static_key = ::core::ptr::addr_of!((*key).$field);
};

$crate::static_key::_static_key_false! { $key, $keytyp, $field }
}};
}

pub use {_static_key_false, static_key_false};
2 changes: 1 addition & 1 deletion scripts/Makefile.build
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# Compile Rust sources (.rs)
# ---------------------------------------------------------------------------

rust_allowed_features := new_uninit
rust_allowed_features := asm_const,asm_goto,new_uninit

# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree
Expand Down