* [PATCH v7 1/5] rust: add generic static_key_false
2024-08-16 11:07 [PATCH v7 0/5] Tracepoints and static branch in Rust Alice Ryhl
@ 2024-08-16 11:07 ` Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 2/5] rust: add tracepoint support Alice Ryhl
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Alice Ryhl @ 2024-08-16 11:07 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg
Cc: linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch, Alice Ryhl
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.
This patch only provides a generic implementation without code patching
(matching the one used when CONFIG_JUMP_LABEL is disabled). Later
patches add support for inline asm implementations that use runtime
patching.
When CONFIG_JUMP_LABEL is unset, `static_key_count` is a static inline
function, so a Rust helper is defined for `static_key_count` in this
case. If Rust is compiled with LTO, this call should get inlined. The
helper can be eliminated once we have the necessary inline asm to make
atomic operations from Rust.
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/helpers.c | 9 +++++++++
rust/kernel/jump_label.rs | 29 +++++++++++++++++++++++++++++
rust/kernel/lib.rs | 1 +
4 files changed, 40 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index b940a5777330..8fd092e1b809 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -14,6 +14,7 @@
#include <linux/ethtool.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
+#include <linux/jump_label.h>
#include <linux/mdio.h>
#include <linux/phy.h>
#include <linux/refcount.h>
diff --git a/rust/helpers.c b/rust/helpers.c
index 92d3c03ae1bd..5a9bf5209cd8 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -28,6 +28,7 @@
#include <linux/errname.h>
#include <linux/gfp.h>
#include <linux/highmem.h>
+#include <linux/jump_label.h>
#include <linux/mutex.h>
#include <linux/refcount.h>
#include <linux/sched/signal.h>
@@ -133,6 +134,14 @@ bool rust_helper_refcount_dec_and_test(refcount_t *r)
}
EXPORT_SYMBOL_GPL(rust_helper_refcount_dec_and_test);
+#ifndef CONFIG_JUMP_LABEL
+int rust_helper_static_key_count(struct static_key *key)
+{
+ return static_key_count(key);
+}
+EXPORT_SYMBOL_GPL(rust_helper_static_key_count);
+#endif
+
__force void *rust_helper_ERR_PTR(long err)
{
return ERR_PTR(err);
diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
new file mode 100644
index 000000000000..011e1fc1d19a
--- /dev/null
+++ b/rust/kernel/jump_label.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2024 Google LLC.
+
+//! Logic for static keys.
+//!
+//! C header: [`include/linux/jump_label.h`](srctree/include/linux/jump_label.h).
+
+/// 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`.
+///
+/// # Safety
+///
+/// The macro must be used with a real static key defined by C.
+#[macro_export]
+macro_rules! static_key_false {
+ ($key:path, $keytyp:ty, $field:ident) => {{
+ let _key: *const $keytyp = ::core::ptr::addr_of!($key);
+ let _key: *const $crate::bindings::static_key = ::core::ptr::addr_of!((*_key).$field);
+
+ $crate::bindings::static_key_count(_key.cast_mut()) > 0
+ }};
+}
+pub use static_key_false;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 274bdc1b0a82..91af9f75d121 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -36,6 +36,7 @@
pub mod firmware;
pub mod init;
pub mod ioctl;
+pub mod jump_label;
#[cfg(CONFIG_KUNIT)]
pub mod kunit;
#[cfg(CONFIG_NET)]
--
2.46.0.184.g6999bdac58-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 2/5] rust: add tracepoint support
2024-08-16 11:07 [PATCH v7 0/5] Tracepoints and static branch in Rust Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 1/5] rust: add generic static_key_false Alice Ryhl
@ 2024-08-16 11:07 ` Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 3/5] rust: samples: add tracepoint to Rust sample Alice Ryhl
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Alice Ryhl @ 2024-08-16 11:07 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg
Cc: linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch, Alice Ryhl,
Carlos Llamas
Make it possible to have Rust code call into tracepoints defined by C
code. It is still required that the tracepoint is declared in a C
header, and that this header is included in the input to bindgen.
Instead of calling __DO_TRACE directly, the exported rust_do_trace_
function calls an inline helper function. This is because the `cond`
argument does not exist at the callsite of DEFINE_RUST_DO_TRACE.
__DECLARE_TRACE always emits an inline static and an extern declaration
that is only used when CREATE_RUST_TRACE_POINTS is set. These should not
end up in the final binary so it is not a problem that they sometimes
are emitted without a user.
Reviewed-by: Carlos Llamas <cmllamas@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
include/linux/tracepoint.h | 22 +++++++++++++++++-
include/trace/define_trace.h | 12 ++++++++++
rust/bindings/bindings_helper.h | 1 +
rust/kernel/lib.rs | 1 +
rust/kernel/tracepoint.rs | 49 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 6be396bb4297..5042ca588e41 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -237,6 +237,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
#define __DECLARE_TRACE_RCU(name, proto, args, cond)
#endif
+/*
+ * Declare an exported function that Rust code can call to trigger this
+ * tracepoint. This function does not include the static branch; that is done
+ * in Rust to avoid a function call when the tracepoint is disabled.
+ */
+#define DEFINE_RUST_DO_TRACE(name, proto, args)
+#define __DEFINE_RUST_DO_TRACE(name, proto, args) \
+ notrace void rust_do_trace_##name(proto) \
+ { \
+ __rust_do_trace_##name(args); \
+ }
+
/*
* Make sure the alignment of the structure in the __tracepoints section will
* not add unwanted padding between the beginning of the section and the
@@ -252,6 +264,13 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
extern int __traceiter_##name(data_proto); \
DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name); \
extern struct tracepoint __tracepoint_##name; \
+ extern void rust_do_trace_##name(proto); \
+ static inline void __rust_do_trace_##name(proto) \
+ { \
+ __DO_TRACE(name, \
+ TP_ARGS(args), \
+ TP_CONDITION(cond), 0); \
+ } \
static inline void trace_##name(proto) \
{ \
if (static_key_false(&__tracepoint_##name.key)) \
@@ -336,7 +355,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
void __probestub_##_name(void *__data, proto) \
{ \
} \
- DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name);
+ DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name); \
+ DEFINE_RUST_DO_TRACE(_name, TP_PROTO(proto), TP_ARGS(args))
#define DEFINE_TRACE(name, proto, args) \
DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index 00723935dcc7..8159294c2041 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -72,6 +72,13 @@
#define DECLARE_TRACE(name, proto, args) \
DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
+/* If requested, create helpers for calling these tracepoints from Rust. */
+#ifdef CREATE_RUST_TRACE_POINTS
+#undef DEFINE_RUST_DO_TRACE
+#define DEFINE_RUST_DO_TRACE(name, proto, args) \
+ __DEFINE_RUST_DO_TRACE(name, PARAMS(proto), PARAMS(args))
+#endif
+
#undef TRACE_INCLUDE
#undef __TRACE_INCLUDE
@@ -129,6 +136,11 @@
# undef UNDEF_TRACE_INCLUDE_PATH
#endif
+#ifdef CREATE_RUST_TRACE_POINTS
+# undef DEFINE_RUST_DO_TRACE
+# define DEFINE_RUST_DO_TRACE(name, proto, args)
+#endif
+
/* We may be processing more files */
#define CREATE_TRACE_POINTS
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 8fd092e1b809..fc6f94729789 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -20,6 +20,7 @@
#include <linux/refcount.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/tracepoint.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 91af9f75d121..d00a44b000b6 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -51,6 +51,7 @@
pub mod sync;
pub mod task;
pub mod time;
+pub mod tracepoint;
pub mod types;
pub mod uaccess;
pub mod workqueue;
diff --git a/rust/kernel/tracepoint.rs b/rust/kernel/tracepoint.rs
new file mode 100644
index 000000000000..cf2d9ad15912
--- /dev/null
+++ b/rust/kernel/tracepoint.rs
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2024 Google LLC.
+
+//! Logic for tracepoints.
+
+/// Declare the Rust entry point for a tracepoint.
+///
+/// This macro generates an unsafe function that calls into C, and its safety requirements will be
+/// whatever the relevant C code requires. To document these safety requirements, you may add
+/// doc-comments when invoking the macro.
+#[macro_export]
+macro_rules! declare_trace {
+ ($($(#[$attr:meta])* $pub:vis unsafe fn $name:ident($($argname:ident : $argtyp:ty),* $(,)?);)*) => {$(
+ $( #[$attr] )*
+ #[inline(always)]
+ $pub unsafe fn $name($($argname : $argtyp),*) {
+ #[cfg(CONFIG_TRACEPOINTS)]
+ {
+ // SAFETY: It's always okay to query the static key for a tracepoint.
+ let should_trace = unsafe {
+ $crate::macros::paste! {
+ $crate::jump_label::static_key_false!(
+ $crate::bindings::[< __tracepoint_ $name >],
+ $crate::bindings::tracepoint,
+ key
+ )
+ }
+ };
+
+ if should_trace {
+ $crate::macros::paste! {
+ // SAFETY: The caller guarantees that it is okay to call this tracepoint.
+ unsafe { $crate::bindings::[< rust_do_trace_ $name >]($($argname),*) };
+ }
+ }
+ }
+
+ #[cfg(not(CONFIG_TRACEPOINTS))]
+ {
+ // If tracepoints are disabled, insert a trivial use of each argument
+ // to avoid unused argument warnings.
+ $( let _unused = $argname; )*
+ }
+ }
+ )*}
+}
+
+pub use declare_trace;
--
2.46.0.184.g6999bdac58-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 3/5] rust: samples: add tracepoint to Rust sample
2024-08-16 11:07 [PATCH v7 0/5] Tracepoints and static branch in Rust Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 1/5] rust: add generic static_key_false Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 2/5] rust: add tracepoint support Alice Ryhl
@ 2024-08-16 11:07 ` Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 4/5] jump_label: adjust inline asm to be consistent Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 5/5] rust: add arch_static_branch Alice Ryhl
4 siblings, 0 replies; 9+ messages in thread
From: Alice Ryhl @ 2024-08-16 11:07 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg
Cc: linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch, Alice Ryhl
This updates the Rust printing sample to invoke a tracepoint. This
ensures that we have a user in-tree from the get-go even though the
patch is being merged before its real user.
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
MAINTAINERS | 1 +
include/trace/events/rust_sample.h | 31 +++++++++++++++++++++++++++++++
rust/bindings/bindings_helper.h | 1 +
samples/rust/Makefile | 3 ++-
samples/rust/rust_print.rs | 18 ++++++++++++++++++
samples/rust/rust_print_events.c | 8 ++++++++
6 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index f328373463b0..1acf5bfddfc4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19922,6 +19922,7 @@ C: zulip://rust-for-linux.zulipchat.com
P: https://rust-for-linux.com/contributing
T: git https://github.com/Rust-for-Linux/linux.git rust-next
F: Documentation/rust/
+F: include/trace/events/rust_sample.h
F: rust/
F: samples/rust/
F: scripts/*rust*
diff --git a/include/trace/events/rust_sample.h b/include/trace/events/rust_sample.h
new file mode 100644
index 000000000000..dbc80ca2e465
--- /dev/null
+++ b/include/trace/events/rust_sample.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Tracepoints for `samples/rust/rust_print.rs`.
+ *
+ * Copyright (C) 2024 Google, Inc.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rust_sample
+
+#if !defined(_RUST_SAMPLE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _RUST_SAMPLE_TRACE_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(rust_sample_loaded,
+ TP_PROTO(int magic_number),
+ TP_ARGS(magic_number),
+ TP_STRUCT__entry(
+ __field(int, magic_number)
+ ),
+ TP_fast_assign(
+ __entry->magic_number = magic_number;
+ ),
+ TP_printk("magic=%d", __entry->magic_number)
+);
+
+#endif /* _RUST_SAMPLE_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index fc6f94729789..fe97256afe65 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -23,6 +23,7 @@
#include <linux/tracepoint.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <trace/events/rust_sample.h>
/* `bindgen` gets confused at certain things. */
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 03086dabbea4..f29280ec4820 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
+ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
-obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o rust_print_events.o
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
index 6eabb0d79ea3..6d14b08cac1c 100644
--- a/samples/rust/rust_print.rs
+++ b/samples/rust/rust_print.rs
@@ -69,6 +69,8 @@ fn init(_module: &'static ThisModule) -> Result<Self> {
arc_print()?;
+ trace::trace_rust_sample_loaded(42);
+
Ok(RustPrint)
}
}
@@ -78,3 +80,19 @@ fn drop(&mut self) {
pr_info!("Rust printing macros sample (exit)\n");
}
}
+
+mod trace {
+ use core::ffi::c_int;
+
+ kernel::declare_trace! {
+ /// # Safety
+ ///
+ /// Always safe to call.
+ unsafe fn rust_sample_loaded(magic: c_int);
+ }
+
+ pub(crate) fn trace_rust_sample_loaded(magic: i32) {
+ // SAFETY: Always safe to call.
+ unsafe { rust_sample_loaded(magic as c_int) }
+ }
+}
diff --git a/samples/rust/rust_print_events.c b/samples/rust/rust_print_events.c
new file mode 100644
index 000000000000..a9169ff0edf1
--- /dev/null
+++ b/samples/rust/rust_print_events.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2024 Google LLC
+ */
+
+#define CREATE_TRACE_POINTS
+#define CREATE_RUST_TRACE_POINTS
+#include <trace/events/rust_sample.h>
--
2.46.0.184.g6999bdac58-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 4/5] jump_label: adjust inline asm to be consistent
2024-08-16 11:07 [PATCH v7 0/5] Tracepoints and static branch in Rust Alice Ryhl
` (2 preceding siblings ...)
2024-08-16 11:07 ` [PATCH v7 3/5] rust: samples: add tracepoint to Rust sample Alice Ryhl
@ 2024-08-16 11:07 ` Alice Ryhl
2024-08-16 11:07 ` [PATCH v7 5/5] rust: add arch_static_branch Alice Ryhl
4 siblings, 0 replies; 9+ messages in thread
From: Alice Ryhl @ 2024-08-16 11:07 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg
Cc: linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch, Alice Ryhl
To avoid duplication of inline asm between C and Rust, we need to
import the inline asm from the relevant `jump_label.h` header into Rust.
To make that easier, this patch updates the header files to expose the
inline asm via a new ARCH_STATIC_BRANCH_ASM macro.
The header files are all updated to define a ARCH_STATIC_BRANCH_ASM that
takes the same arguments in a consistent order so that Rust can use the
same logic for every architecture.
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
arch/arm/include/asm/jump_label.h | 14 +++++----
arch/arm64/include/asm/jump_label.h | 20 ++++++++-----
arch/loongarch/include/asm/jump_label.h | 16 +++++++----
arch/riscv/include/asm/jump_label.h | 50 ++++++++++++++++++---------------
arch/x86/include/asm/jump_label.h | 38 ++++++++++---------------
5 files changed, 75 insertions(+), 63 deletions(-)
diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h
index e4eb54f6cd9f..a35aba7f548c 100644
--- a/arch/arm/include/asm/jump_label.h
+++ b/arch/arm/include/asm/jump_label.h
@@ -9,13 +9,17 @@
#define JUMP_LABEL_NOP_SIZE 4
+/* This macro is also expanded on the Rust side. */
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1:\n\t" \
+ WASM(nop) "\n\t" \
+ ".pushsection __jump_table, \"aw\"\n\t" \
+ ".word 1b, " label ", " key "\n\t" \
+ ".popsection\n\t" \
+
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
- asm goto("1:\n\t"
- WASM(nop) "\n\t"
- ".pushsection __jump_table, \"aw\"\n\t"
- ".word 1b, %l[l_yes], %c0\n\t"
- ".popsection\n\t"
+ asm goto(ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]")
: : "i" (&((char *)key)[branch]) : : l_yes);
return false;
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h
index a0a5bbae7229..424ed421cd97 100644
--- a/arch/arm64/include/asm/jump_label.h
+++ b/arch/arm64/include/asm/jump_label.h
@@ -19,10 +19,14 @@
#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\"\n\t" \
".align 3\n\t" \
- ".long 1b - ., %l["#label"] - .\n\t" \
- ".quad %c0 - .\n\t" \
- ".popsection\n\t" \
- : : "i"(key) : : label
+ ".long 1b - ., " label " - .\n\t" \
+ ".quad " key " - .\n\t" \
+ ".popsection\n\t"
+
+/* This macro is also expanded on the Rust side. */
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1: nop\n\t" \
+ JUMP_TABLE_ENTRY(key, label)
static __always_inline bool arch_static_branch(struct static_key * const key,
const bool branch)
@@ -30,8 +34,8 @@ static __always_inline bool arch_static_branch(struct static_key * const key,
char *k = &((char *)key)[branch];
asm goto(
- "1: nop \n\t"
- JUMP_TABLE_ENTRY(k, l_yes)
+ ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]")
+ : : "i"(k) : : l_yes
);
return false;
@@ -43,9 +47,11 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke
const bool branch)
{
char *k = &((char *)key)[branch];
+
asm goto(
"1: b %l[l_yes] \n\t"
- JUMP_TABLE_ENTRY(k, l_yes)
+ JUMP_TABLE_ENTRY("%c0", "%l[l_yes]")
+ : : "i"(k) : : l_yes
);
return false;
l_yes:
diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h
index 29acfe3de3fa..8a924bd69d19 100644
--- a/arch/loongarch/include/asm/jump_label.h
+++ b/arch/loongarch/include/asm/jump_label.h
@@ -13,18 +13,22 @@
#define JUMP_LABEL_NOP_SIZE 4
-#define JUMP_TABLE_ENTRY \
+/* This macro is also expanded on the Rust side. */
+#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\" \n\t" \
".align 3 \n\t" \
- ".long 1b - ., %l[l_yes] - . \n\t" \
- ".quad %0 - . \n\t" \
+ ".long 1b - ., " label " - . \n\t" \
+ ".quad " key " - . \n\t" \
".popsection \n\t"
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1: nop \n\t" \
+ JUMP_TABLE_ENTRY(key, label)
+
static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
asm goto(
- "1: nop \n\t"
- JUMP_TABLE_ENTRY
+ ARCH_STATIC_BRANCH_ASM("%0", "%l[l_yes]")
: : "i"(&((char *)key)[branch]) : : l_yes);
return false;
@@ -37,7 +41,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke
{
asm goto(
"1: b %l[l_yes] \n\t"
- JUMP_TABLE_ENTRY
+ JUMP_TABLE_ENTRY("%0", "%l[l_yes]")
: : "i"(&((char *)key)[branch]) : : l_yes);
return false;
diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
index 1c768d02bd0c..87a71cc6d146 100644
--- a/arch/riscv/include/asm/jump_label.h
+++ b/arch/riscv/include/asm/jump_label.h
@@ -16,21 +16,28 @@
#define JUMP_LABEL_NOP_SIZE 4
+#define JUMP_TABLE_ENTRY(key, label) \
+ ".pushsection __jump_table, \"aw\" \n\t" \
+ ".align " RISCV_LGPTR " \n\t" \
+ ".long 1b - ., " label " - . \n\t" \
+ "" RISCV_PTR " " key " - . \n\t" \
+ ".popsection \n\t"
+
+/* This macro is also expanded on the Rust side. */
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ " .align 2 \n\t" \
+ " .option push \n\t" \
+ " .option norelax \n\t" \
+ " .option norvc \n\t" \
+ "1: nop \n\t" \
+ " .option pop \n\t" \
+ JUMP_TABLE_ENTRY(key, label)
+
static __always_inline bool arch_static_branch(struct static_key * const key,
const bool branch)
{
asm goto(
- " .align 2 \n\t"
- " .option push \n\t"
- " .option norelax \n\t"
- " .option norvc \n\t"
- "1: nop \n\t"
- " .option pop \n\t"
- " .pushsection __jump_table, \"aw\" \n\t"
- " .align " RISCV_LGPTR " \n\t"
- " .long 1b - ., %l[label] - . \n\t"
- " " RISCV_PTR " %0 - . \n\t"
- " .popsection \n\t"
+ ARCH_STATIC_BRANCH_ASM("%0", "%l[label]")
: : "i"(&((char *)key)[branch]) : : label);
return false;
@@ -38,21 +45,20 @@ static __always_inline bool arch_static_branch(struct static_key * const key,
return true;
}
+#define ARCH_STATIC_BRANCH_JUMP_ASM(key, label) \
+ " .align 2 \n\t" \
+ " .option push \n\t" \
+ " .option norelax \n\t" \
+ " .option norvc \n\t" \
+ "1: j " label " \n\t" \
+ " .option pop \n\t" \
+ JUMP_TABLE_ENTRY(key, label)
+
static __always_inline bool arch_static_branch_jump(struct static_key * const key,
const bool branch)
{
asm goto(
- " .align 2 \n\t"
- " .option push \n\t"
- " .option norelax \n\t"
- " .option norvc \n\t"
- "1: j %l[label] \n\t"
- " .option pop \n\t"
- " .pushsection __jump_table, \"aw\" \n\t"
- " .align " RISCV_LGPTR " \n\t"
- " .long 1b - ., %l[label] - . \n\t"
- " " RISCV_PTR " %0 - . \n\t"
- " .popsection \n\t"
+ ARCH_STATIC_BRANCH_JUMP_ASM("%0", "%l[label]")
: : "i"(&((char *)key)[branch]) : : label);
return false;
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index cbbef32517f0..fb79fa1cf70a 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -12,49 +12,41 @@
#include <linux/stringify.h>
#include <linux/types.h>
-#define JUMP_TABLE_ENTRY \
+#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\" \n\t" \
_ASM_ALIGN "\n\t" \
".long 1b - . \n\t" \
- ".long %l[l_yes] - . \n\t" \
- _ASM_PTR "%c0 + %c1 - .\n\t" \
+ ".long " label " - . \n\t" \
+ _ASM_PTR " " key " - . \n\t" \
".popsection \n\t"
+/* This macro is also expanded on the Rust side. */
#ifdef CONFIG_HAVE_JUMP_LABEL_HACK
-
-static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
-{
- asm goto("1:"
- "jmp %l[l_yes] # objtool NOPs this \n\t"
- JUMP_TABLE_ENTRY
- : : "i" (key), "i" (2 | branch) : : l_yes);
-
- return false;
-l_yes:
- return true;
-}
-
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1: jmp " label " # objtool NOPs this \n\t" \
+ JUMP_TABLE_ENTRY(key, label)
#else /* !CONFIG_HAVE_JUMP_LABEL_HACK */
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1: .byte " __stringify(BYTES_NOP5) "\n\t" \
+ JUMP_TABLE_ENTRY(key, label)
+#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */
static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
- asm goto("1:"
- ".byte " __stringify(BYTES_NOP5) "\n\t"
- JUMP_TABLE_ENTRY
- : : "i" (key), "i" (branch) : : l_yes);
+ int hack_bit = IS_ENABLED(CONFIG_HAVE_JUMP_LABEL_HACK) ? 2 : 0;
+ asm goto(ARCH_STATIC_BRANCH_ASM("%c0 + %c1", "%l[l_yes]")
+ : : "i" (key), "i" (hack_bit | branch) : : l_yes);
return false;
l_yes:
return true;
}
-#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */
-
static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
asm goto("1:"
"jmp %l[l_yes]\n\t"
- JUMP_TABLE_ENTRY
+ JUMP_TABLE_ENTRY("%c0 + %c1", "%l[l_yes]")
: : "i" (key), "i" (branch) : : l_yes);
return false;
--
2.46.0.184.g6999bdac58-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 5/5] rust: add arch_static_branch
2024-08-16 11:07 [PATCH v7 0/5] Tracepoints and static branch in Rust Alice Ryhl
` (3 preceding siblings ...)
2024-08-16 11:07 ` [PATCH v7 4/5] jump_label: adjust inline asm to be consistent Alice Ryhl
@ 2024-08-16 11:07 ` Alice Ryhl
2024-08-21 17:08 ` Boqun Feng
4 siblings, 1 reply; 9+ messages in thread
From: Alice Ryhl @ 2024-08-16 11:07 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg
Cc: linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch, Alice Ryhl
To allow the Rust implementation of static_key_false to use runtime code
patching instead of the generic implementation, pull in the relevant
inline assembly from the jump_label.h header by running the C
preprocessor on a .rs.S file. Build rules are added for .rs.S files.
Since the relevant inline asm has been adjusted to export the inline asm
via the ARCH_STATIC_BRANCH_ASM macro in a consistent way, the Rust side
does not need architecture specific code to pull in the asm.
It is not possible to use the existing C implementation of
arch_static_branch via a Rust helper because it passes the argument
`key` to inline assembly as an 'i' parameter. Any attempt to add a C
helper for this function will fail to compile because the value of `key`
must be known at compile-time.
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/Makefile | 5 ++-
rust/kernel/.gitignore | 3 ++
rust/kernel/arch_static_branch_asm.rs.S | 7 ++++
rust/kernel/jump_label.rs | 64 ++++++++++++++++++++++++++++++++-
rust/kernel/lib.rs | 30 ++++++++++++++++
scripts/Makefile.build | 9 ++++-
6 files changed, 115 insertions(+), 3 deletions(-)
diff --git a/rust/Makefile b/rust/Makefile
index 199e0db67962..277fcef656b8 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -14,6 +14,8 @@ CFLAGS_REMOVE_helpers.o = -Wmissing-prototypes -Wmissing-declarations
always-$(CONFIG_RUST) += libmacros.so
no-clean-files += libmacros.so
+always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/arch_static_branch_asm.rs
+
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
@@ -409,7 +411,8 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
- $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
+ $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o \
+ $(obj)/kernel/arch_static_branch_asm.rs FORCE
+$(call if_changed_rule,rustc_library)
endif # CONFIG_RUST
diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore
new file mode 100644
index 000000000000..d082731007c6
--- /dev/null
+++ b/rust/kernel/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+/arch_static_branch_asm.rs
diff --git a/rust/kernel/arch_static_branch_asm.rs.S b/rust/kernel/arch_static_branch_asm.rs.S
new file mode 100644
index 000000000000..9e373d4f7567
--- /dev/null
+++ b/rust/kernel/arch_static_branch_asm.rs.S
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/jump_label.h>
+
+// Cut here.
+
+::kernel::concat_literals!(ARCH_STATIC_BRANCH_ASM("{symb} + {off} + {branch}", "{l_yes}"))
diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
index 011e1fc1d19a..7757e4f8e85e 100644
--- a/rust/kernel/jump_label.rs
+++ b/rust/kernel/jump_label.rs
@@ -23,7 +23,69 @@ macro_rules! static_key_false {
let _key: *const $keytyp = ::core::ptr::addr_of!($key);
let _key: *const $crate::bindings::static_key = ::core::ptr::addr_of!((*_key).$field);
- $crate::bindings::static_key_count(_key.cast_mut()) > 0
+ #[cfg(not(CONFIG_JUMP_LABEL))]
+ {
+ $crate::bindings::static_key_count(_key.cast_mut()) > 0
+ }
+
+ #[cfg(CONFIG_JUMP_LABEL)]
+ $crate::jump_label::arch_static_branch! { $key, $keytyp, $field, false }
}};
}
pub use static_key_false;
+
+/// Assert that the assembly block evaluates to a string literal.
+#[cfg(CONFIG_JUMP_LABEL)]
+const _: &str = include!("arch_static_branch_asm.rs");
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(CONFIG_JUMP_LABEL)]
+#[cfg(not(CONFIG_HAVE_JUMP_LABEL_HACK))]
+macro_rules! arch_static_branch {
+ ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
+ $crate::asm!(
+ include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
+ l_yes = label {
+ break 'my_label true;
+ },
+ symb = sym $key,
+ off = const ::core::mem::offset_of!($keytyp, $field),
+ branch = const $crate::jump_label::bool_to_int($branch),
+ );
+
+ break 'my_label false;
+ }};
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(CONFIG_JUMP_LABEL)]
+#[cfg(CONFIG_HAVE_JUMP_LABEL_HACK)]
+macro_rules! arch_static_branch {
+ ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
+ $crate::asm!(
+ include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
+ l_yes = label {
+ break 'my_label true;
+ },
+ symb = sym $key,
+ off = const ::core::mem::offset_of!($keytyp, $field),
+ branch = const 2 | $crate::jump_label::bool_to_int($branch),
+ );
+
+ break 'my_label false;
+ }};
+}
+
+#[cfg(CONFIG_JUMP_LABEL)]
+pub use arch_static_branch;
+
+/// A helper used by inline assembly to pass a boolean to as a `const` parameter.
+///
+/// Using this function instead of a cast lets you assert that the input is a boolean, and not some
+/// other type that can also be cast to an integer.
+#[doc(hidden)]
+pub const fn bool_to_int(b: bool) -> i32 {
+ b as i32
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d00a44b000b6..9e9b95ab6966 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -145,3 +145,33 @@ macro_rules! container_of {
ptr.sub(offset) as *const $type
}}
}
+
+/// Helper for `.rs.S` files.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! concat_literals {
+ ($( $asm:literal )* ) => {
+ ::core::concat!($($asm),*)
+ };
+}
+
+/// Wrapper around `asm!` that uses at&t syntax on x86.
+// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
+// syntax.
+#[cfg(target_arch = "x86_64")]
+#[macro_export]
+macro_rules! asm {
+ ($($asm:expr),* ; $($rest:tt)*) => {
+ ::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
+ };
+}
+
+/// Wrapper around `asm!` that uses at&t syntax on x86.
+// For non-x86 arches we just pass through to `asm!`.
+#[cfg(not(target_arch = "x86_64"))]
+#[macro_export]
+macro_rules! asm {
+ ($($asm:expr),* ; $($rest:tt)*) => {
+ ::core::arch::asm!( $($asm)*, $($rest)* )
+ };
+}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 72b1232b1f7d..59fe83fba647 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -263,12 +263,13 @@ $(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
# modules case.
rust_common_cmd = \
+ SRCTREE=$(abspath $(srctree)) \
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
-Zallow-features=$(rust_allowed_features) \
-Zcrate-attr=no_std \
@@ -318,6 +319,12 @@ quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
$(obj)/%.ll: $(obj)/%.rs FORCE
+$(call if_changed_dep,rustc_ll_rs)
+quiet_cmd_rustc_rs_rs_S = RSCPP $(quiet_modtag) $@
+ cmd_rustc_rs_rs_S = $(CPP) $(c_flags) -xc -C -P $< | sed '1,/^\/\/ Cut here.$$/d' >$@
+
+$(obj)/%.rs: $(obj)/%.rs.S FORCE
+ +$(call if_changed_dep,rustc_rs_rs_S)
+
# Compile assembler sources (.S)
# ---------------------------------------------------------------------------
--
2.46.0.184.g6999bdac58-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v7 5/5] rust: add arch_static_branch
2024-08-16 11:07 ` [PATCH v7 5/5] rust: add arch_static_branch Alice Ryhl
@ 2024-08-21 17:08 ` Boqun Feng
2024-08-21 17:54 ` Miguel Ojeda
0 siblings, 1 reply; 9+ messages in thread
From: Boqun Feng @ 2024-08-21 17:08 UTC (permalink / raw)
To: Alice Ryhl
Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch
On Fri, Aug 16, 2024 at 11:07:42AM +0000, Alice Ryhl wrote:
> To allow the Rust implementation of static_key_false to use runtime code
> patching instead of the generic implementation, pull in the relevant
> inline assembly from the jump_label.h header by running the C
> preprocessor on a .rs.S file. Build rules are added for .rs.S files.
>
> Since the relevant inline asm has been adjusted to export the inline asm
> via the ARCH_STATIC_BRANCH_ASM macro in a consistent way, the Rust side
> does not need architecture specific code to pull in the asm.
>
> It is not possible to use the existing C implementation of
> arch_static_branch via a Rust helper because it passes the argument
> `key` to inline assembly as an 'i' parameter. Any attempt to add a C
> helper for this function will fail to compile because the value of `key`
> must be known at compile-time.
>
> Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> rust/Makefile | 5 ++-
> rust/kernel/.gitignore | 3 ++
> rust/kernel/arch_static_branch_asm.rs.S | 7 ++++
> rust/kernel/jump_label.rs | 64 ++++++++++++++++++++++++++++++++-
> rust/kernel/lib.rs | 30 ++++++++++++++++
> scripts/Makefile.build | 9 ++++-
> 6 files changed, 115 insertions(+), 3 deletions(-)
>
> diff --git a/rust/Makefile b/rust/Makefile
> index 199e0db67962..277fcef656b8 100644
> --- a/rust/Makefile
> +++ b/rust/Makefile
> @@ -14,6 +14,8 @@ CFLAGS_REMOVE_helpers.o = -Wmissing-prototypes -Wmissing-declarations
> always-$(CONFIG_RUST) += libmacros.so
> no-clean-files += libmacros.so
>
> +always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/arch_static_branch_asm.rs
> +
> always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
> obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
> always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
> @@ -409,7 +411,8 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
> $(obj)/kernel.o: private rustc_target_flags = --extern alloc \
> --extern build_error --extern macros --extern bindings --extern uapi
> $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
> - $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
> + $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o \
> + $(obj)/kernel/arch_static_branch_asm.rs FORCE
> +$(call if_changed_rule,rustc_library)
>
> endif # CONFIG_RUST
> diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore
> new file mode 100644
> index 000000000000..d082731007c6
> --- /dev/null
> +++ b/rust/kernel/.gitignore
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +/arch_static_branch_asm.rs
> diff --git a/rust/kernel/arch_static_branch_asm.rs.S b/rust/kernel/arch_static_branch_asm.rs.S
> new file mode 100644
> index 000000000000..9e373d4f7567
> --- /dev/null
> +++ b/rust/kernel/arch_static_branch_asm.rs.S
> @@ -0,0 +1,7 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/jump_label.h>
> +
> +// Cut here.
> +
> +::kernel::concat_literals!(ARCH_STATIC_BRANCH_ASM("{symb} + {off} + {branch}", "{l_yes}"))
> diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
> index 011e1fc1d19a..7757e4f8e85e 100644
> --- a/rust/kernel/jump_label.rs
> +++ b/rust/kernel/jump_label.rs
> @@ -23,7 +23,69 @@ macro_rules! static_key_false {
> let _key: *const $keytyp = ::core::ptr::addr_of!($key);
> let _key: *const $crate::bindings::static_key = ::core::ptr::addr_of!((*_key).$field);
>
> - $crate::bindings::static_key_count(_key.cast_mut()) > 0
> + #[cfg(not(CONFIG_JUMP_LABEL))]
> + {
> + $crate::bindings::static_key_count(_key.cast_mut()) > 0
> + }
> +
> + #[cfg(CONFIG_JUMP_LABEL)]
> + $crate::jump_label::arch_static_branch! { $key, $keytyp, $field, false }
> }};
> }
> pub use static_key_false;
> +
> +/// Assert that the assembly block evaluates to a string literal.
> +#[cfg(CONFIG_JUMP_LABEL)]
> +const _: &str = include!("arch_static_branch_asm.rs");
Have you try this with "make O=<dir>"? I hit the following issue, but I
am rebasing on rust-dev, so I might miss something:
error: couldn't read ../rust/kernel/arch_static_branch_asm.rs: No such file or directory (os error 2)
--> ../rust/kernel/jump_label.rs:39:17
|
39 | const _: &str = include!("arch_static_branch_asm.rs");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
Regards,
Boqun
> +
> +#[macro_export]
> +#[doc(hidden)]
> +#[cfg(CONFIG_JUMP_LABEL)]
> +#[cfg(not(CONFIG_HAVE_JUMP_LABEL_HACK))]
> +macro_rules! arch_static_branch {
> + ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
> + $crate::asm!(
> + include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> + l_yes = label {
> + break 'my_label true;
> + },
> + symb = sym $key,
> + off = const ::core::mem::offset_of!($keytyp, $field),
> + branch = const $crate::jump_label::bool_to_int($branch),
> + );
> +
> + break 'my_label false;
> + }};
> +}
> +
> +#[macro_export]
> +#[doc(hidden)]
> +#[cfg(CONFIG_JUMP_LABEL)]
> +#[cfg(CONFIG_HAVE_JUMP_LABEL_HACK)]
> +macro_rules! arch_static_branch {
> + ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
> + $crate::asm!(
> + include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> + l_yes = label {
> + break 'my_label true;
> + },
> + symb = sym $key,
> + off = const ::core::mem::offset_of!($keytyp, $field),
> + branch = const 2 | $crate::jump_label::bool_to_int($branch),
> + );
> +
> + break 'my_label false;
> + }};
> +}
> +
> +#[cfg(CONFIG_JUMP_LABEL)]
> +pub use arch_static_branch;
> +
> +/// A helper used by inline assembly to pass a boolean to as a `const` parameter.
> +///
> +/// Using this function instead of a cast lets you assert that the input is a boolean, and not some
> +/// other type that can also be cast to an integer.
> +#[doc(hidden)]
> +pub const fn bool_to_int(b: bool) -> i32 {
> + b as i32
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index d00a44b000b6..9e9b95ab6966 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -145,3 +145,33 @@ macro_rules! container_of {
> ptr.sub(offset) as *const $type
> }}
> }
> +
> +/// Helper for `.rs.S` files.
> +#[doc(hidden)]
> +#[macro_export]
> +macro_rules! concat_literals {
> + ($( $asm:literal )* ) => {
> + ::core::concat!($($asm),*)
> + };
> +}
> +
> +/// Wrapper around `asm!` that uses at&t syntax on x86.
> +// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
> +// syntax.
> +#[cfg(target_arch = "x86_64")]
> +#[macro_export]
> +macro_rules! asm {
> + ($($asm:expr),* ; $($rest:tt)*) => {
> + ::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
> + };
> +}
> +
> +/// Wrapper around `asm!` that uses at&t syntax on x86.
> +// For non-x86 arches we just pass through to `asm!`.
> +#[cfg(not(target_arch = "x86_64"))]
> +#[macro_export]
> +macro_rules! asm {
> + ($($asm:expr),* ; $($rest:tt)*) => {
> + ::core::arch::asm!( $($asm)*, $($rest)* )
> + };
> +}
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index 72b1232b1f7d..59fe83fba647 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -263,12 +263,13 @@ $(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
> # modules case.
> rust_common_cmd = \
> + SRCTREE=$(abspath $(srctree)) \
> RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
> -Zallow-features=$(rust_allowed_features) \
> -Zcrate-attr=no_std \
> @@ -318,6 +319,12 @@ quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
> $(obj)/%.ll: $(obj)/%.rs FORCE
> +$(call if_changed_dep,rustc_ll_rs)
>
> +quiet_cmd_rustc_rs_rs_S = RSCPP $(quiet_modtag) $@
> + cmd_rustc_rs_rs_S = $(CPP) $(c_flags) -xc -C -P $< | sed '1,/^\/\/ Cut here.$$/d' >$@
> +
> +$(obj)/%.rs: $(obj)/%.rs.S FORCE
> + +$(call if_changed_dep,rustc_rs_rs_S)
> +
> # Compile assembler sources (.S)
> # ---------------------------------------------------------------------------
>
>
> --
> 2.46.0.184.g6999bdac58-goog
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v7 5/5] rust: add arch_static_branch
2024-08-21 17:08 ` Boqun Feng
@ 2024-08-21 17:54 ` Miguel Ojeda
2024-08-21 18:16 ` Boqun Feng
0 siblings, 1 reply; 9+ messages in thread
From: Miguel Ojeda @ 2024-08-21 17:54 UTC (permalink / raw)
To: Boqun Feng
Cc: Alice Ryhl, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch
[-- Attachment #1: Type: text/plain, Size: 948 bytes --]
On Wed, Aug 21, 2024 at 7:08 PM Boqun Feng <boqun.feng@gmail.com> wrote:
>
> Have you try this with "make O=<dir>"? I hit the following issue, but I
> am rebasing on rust-dev, so I might miss something:
>
> error: couldn't read ../rust/kernel/arch_static_branch_asm.rs: No such file or directory (os error 2)
> --> ../rust/kernel/jump_label.rs:39:17
> |
> 39 | const _: &str = include!("arch_static_branch_asm.rs");
> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> |
> = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
>
> error: aborting due to 1 previous error
Yeah, we should use a `*TREE` everywhere. In addition, we should not
use `SRCTREE` but `OBJTREE`. It is my fault, this comes from my
prototype I gave Alice.
Please see the attached diff.
Cheers,
Miguel
[-- Attachment #2: objtree.diff --]
[-- Type: text/x-patch, Size: 1947 bytes --]
diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
index 7757e4f8e85e..ccfd20589c21 100644
--- a/rust/kernel/jump_label.rs
+++ b/rust/kernel/jump_label.rs
@@ -36,7 +36,7 @@ macro_rules! static_key_false {
/// Assert that the assembly block evaluates to a string literal.
#[cfg(CONFIG_JUMP_LABEL)]
-const _: &str = include!("arch_static_branch_asm.rs");
+const _: &str = include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
#[macro_export]
#[doc(hidden)]
@@ -45,7 +45,7 @@ macro_rules! static_key_false {
macro_rules! arch_static_branch {
($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
$crate::asm!(
- include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
l_yes = label {
break 'my_label true;
},
@@ -65,7 +65,7 @@ macro_rules! arch_static_branch {
macro_rules! arch_static_branch {
($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
$crate::asm!(
- include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
l_yes = label {
break 'my_label true;
},
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4f0f6b13ebd7..746cce80545f 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -269,7 +269,7 @@ rust_allowed_features := asm_const,asm_goto,new_uninit
# current working directory, which may be not accessible in the out-of-tree
# modules case.
rust_common_cmd = \
- SRCTREE=$(abspath $(srctree)) \
+ OBJTREE=$(abspath $(objtree)) \
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
-Zallow-features=$(rust_allowed_features) \
-Zcrate-attr=no_std \
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v7 5/5] rust: add arch_static_branch
2024-08-21 17:54 ` Miguel Ojeda
@ 2024-08-21 18:16 ` Boqun Feng
0 siblings, 0 replies; 9+ messages in thread
From: Boqun Feng @ 2024-08-21 18:16 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Alice Ryhl, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
linux-trace-kernel, rust-for-linux, linux-kernel, Arnd Bergmann,
linux-arch, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Sean Christopherson,
Uros Bizjak, Catalin Marinas, Will Deacon, Marc Zyngier,
Oliver Upton, Mark Rutland, Ryan Roberts, Fuad Tabba,
linux-arm-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Anup Patel, Andrew Jones, Alexandre Ghiti, Conor Dooley,
Samuel Holland, linux-riscv, Huacai Chen, WANG Xuerui, Bibo Mao,
Tiezhu Yang, Andrew Morton, Tianrui Zhao, loongarch
On Wed, Aug 21, 2024 at 07:54:51PM +0200, Miguel Ojeda wrote:
> On Wed, Aug 21, 2024 at 7:08 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> >
> > Have you try this with "make O=<dir>"? I hit the following issue, but I
> > am rebasing on rust-dev, so I might miss something:
> >
> > error: couldn't read ../rust/kernel/arch_static_branch_asm.rs: No such file or directory (os error 2)
> > --> ../rust/kernel/jump_label.rs:39:17
> > |
> > 39 | const _: &str = include!("arch_static_branch_asm.rs");
> > | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > |
> > = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
> >
> > error: aborting due to 1 previous error
>
> Yeah, we should use a `*TREE` everywhere. In addition, we should not
> use `SRCTREE` but `OBJTREE`. It is my fault, this comes from my
> prototype I gave Alice.
>
> Please see the attached diff.
>
Yes, this fix works, thanks!
Regards,
Boqun
> Cheers,
> Miguel
> diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
> index 7757e4f8e85e..ccfd20589c21 100644
> --- a/rust/kernel/jump_label.rs
> +++ b/rust/kernel/jump_label.rs
> @@ -36,7 +36,7 @@ macro_rules! static_key_false {
>
> /// Assert that the assembly block evaluates to a string literal.
> #[cfg(CONFIG_JUMP_LABEL)]
> -const _: &str = include!("arch_static_branch_asm.rs");
> +const _: &str = include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
>
> #[macro_export]
> #[doc(hidden)]
> @@ -45,7 +45,7 @@ macro_rules! static_key_false {
> macro_rules! arch_static_branch {
> ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
> $crate::asm!(
> - include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> + include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> l_yes = label {
> break 'my_label true;
> },
> @@ -65,7 +65,7 @@ macro_rules! arch_static_branch {
> macro_rules! arch_static_branch {
> ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
> $crate::asm!(
> - include!(concat!(env!("SRCTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> + include!(concat!(env!("OBJTREE"), "/rust/kernel/arch_static_branch_asm.rs"));
> l_yes = label {
> break 'my_label true;
> },
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index 4f0f6b13ebd7..746cce80545f 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -269,7 +269,7 @@ rust_allowed_features := asm_const,asm_goto,new_uninit
> # current working directory, which may be not accessible in the out-of-tree
> # modules case.
> rust_common_cmd = \
> - SRCTREE=$(abspath $(srctree)) \
> + OBJTREE=$(abspath $(objtree)) \
> RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
> -Zallow-features=$(rust_allowed_features) \
> -Zcrate-attr=no_std \
^ permalink raw reply [flat|nested] 9+ messages in thread