mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 00:35:01 +00:00
Add Rust support for trace events:
- Allow Rust code to have trace events Trace events is a popular way to debug what is happening inside the kernel or just to find out what is happening. Rust code is being added to the Linux kernel but it currently does not support the tracing infrastructure. Add support of trace events inside Rust code. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZ0DjqhQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qrLlAPsF6t/c1nHSGTKDv9FJDJe4JHdP7e+U 7X0S8BmSTKFNAQD+K2TEd0bjVP7ug8dQZBT+fveiFr+ARYxAwJ3JnEFjUwg= =Ab+T -----END PGP SIGNATURE----- Merge tag 'trace-rust-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull rust trace event support from Steven Rostedt: "Allow Rust code to have trace events Trace events is a popular way to debug what is happening inside the kernel or just to find out what is happening. Rust code is being added to the Linux kernel but it currently does not support the tracing infrastructure. Add support of trace events inside Rust code" * tag 'trace-rust-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rust: jump_label: skip formatting generated file jump_label: rust: pass a mut ptr to `static_key_count` samples: rust: fix `rust_print` build making it a combined module rust: add arch_static_branch jump_label: adjust inline asm to be consistent rust: samples: add tracepoint to Rust sample rust: add tracepoint support rust: add static_branch_unlikely for static_key_false
This commit is contained in:
commit
7f4f3b14e8
@ -20348,6 +20348,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*
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -12,35 +12,28 @@
|
||||
#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 " + 2", 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
|
||||
asm goto(ARCH_STATIC_BRANCH_ASM("%c0 + %c1", "%l[l_yes]")
|
||||
: : "i" (key), "i" (branch) : : l_yes);
|
||||
|
||||
return false;
|
||||
@ -48,13 +41,11 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co
|
||||
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;
|
||||
|
@ -239,6 +239,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
||||
preempt_enable_notrace(); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -254,6 +266,7 @@ 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 int \
|
||||
register_trace_##name(void (*probe)(data_proto), void *data) \
|
||||
{ \
|
||||
@ -285,6 +298,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
||||
|
||||
#define __DECLARE_TRACE(name, proto, args, cond, data_proto) \
|
||||
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_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_branch_unlikely(&__tracepoint_##name.key)) \
|
||||
@ -299,6 +318,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
||||
|
||||
#define __DECLARE_TRACE_SYSCALL(name, proto, args, cond, data_proto) \
|
||||
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_proto)) \
|
||||
static inline void __rust_do_trace_##name(proto) \
|
||||
{ \
|
||||
__DO_TRACE(name, \
|
||||
TP_ARGS(args), \
|
||||
TP_CONDITION(cond), 1); \
|
||||
} \
|
||||
static inline void trace_##name(proto) \
|
||||
{ \
|
||||
might_fault(); \
|
||||
@ -354,7 +379,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_FN(_name, _reg, _unreg, _proto, _args) \
|
||||
static struct tracepoint_ext __tracepoint_ext_##_name = { \
|
||||
|
@ -76,6 +76,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
|
||||
|
||||
@ -134,6 +141,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
|
||||
|
||||
|
31
include/trace/events/rust_sample.h
Normal file
31
include/trace/events/rust_sample.h
Normal file
@ -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>
|
@ -36,6 +36,8 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
|
||||
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
|
||||
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
|
||||
|
||||
always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs
|
||||
|
||||
# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
|
||||
ifdef CONFIG_RUST
|
||||
|
||||
@ -424,4 +426,8 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
|
||||
$(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
|
||||
+$(call if_changed_rule,rustc_library)
|
||||
|
||||
ifdef CONFIG_JUMP_LABEL
|
||||
$(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs
|
||||
endif
|
||||
|
||||
endif # CONFIG_RUST
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
@ -25,8 +26,10 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/slab.h>
|
||||
#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;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "cred.c"
|
||||
#include "err.c"
|
||||
#include "fs.c"
|
||||
#include "jump_label.c"
|
||||
#include "kunit.c"
|
||||
#include "mutex.c"
|
||||
#include "page.c"
|
||||
|
14
rust/helpers/jump_label.c
Normal file
14
rust/helpers/jump_label.c
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Google LLC.
|
||||
*/
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
#ifndef CONFIG_JUMP_LABEL
|
||||
int rust_helper_static_key_count(struct static_key *key)
|
||||
{
|
||||
return static_key_count(key);
|
||||
}
|
||||
#endif
|
3
rust/kernel/.gitignore
vendored
Normal file
3
rust/kernel/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/generated_arch_static_branch_asm.rs
|
7
rust/kernel/generated_arch_static_branch_asm.rs.S
Normal file
7
rust/kernel/generated_arch_static_branch_asm.rs.S
Normal file
@ -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}"))
|
74
rust/kernel/jump_label.rs
Normal file
74
rust/kernel/jump_label.rs
Normal file
@ -0,0 +1,74 @@
|
||||
// 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_branch_unlikely {
|
||||
($key:path, $keytyp:ty, $field:ident) => {{
|
||||
let _key: *const $keytyp = ::core::ptr::addr_of!($key);
|
||||
let _key: *const $crate::bindings::static_key_false = ::core::ptr::addr_of!((*_key).$field);
|
||||
let _key: *const $crate::bindings::static_key = _key.cast();
|
||||
|
||||
#[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_branch_unlikely;
|
||||
|
||||
/// Assert that the assembly block evaluates to a string literal.
|
||||
#[cfg(CONFIG_JUMP_LABEL)]
|
||||
const _: &str = include!(concat!(
|
||||
env!("OBJTREE"),
|
||||
"/rust/kernel/generated_arch_static_branch_asm.rs"
|
||||
));
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
#[cfg(CONFIG_JUMP_LABEL)]
|
||||
macro_rules! arch_static_branch {
|
||||
($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
|
||||
$crate::asm!(
|
||||
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_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;
|
||||
}};
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
@ -38,6 +38,7 @@
|
||||
pub mod fs;
|
||||
pub mod init;
|
||||
pub mod ioctl;
|
||||
pub mod jump_label;
|
||||
#[cfg(CONFIG_KUNIT)]
|
||||
pub mod kunit;
|
||||
pub mod list;
|
||||
@ -57,6 +58,7 @@
|
||||
pub mod sync;
|
||||
pub mod task;
|
||||
pub mod time;
|
||||
pub mod tracepoint;
|
||||
pub mod types;
|
||||
pub mod uaccess;
|
||||
pub mod workqueue;
|
||||
@ -150,3 +152,38 @@ 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!` configured for use in the kernel.
|
||||
///
|
||||
/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
|
||||
/// syntax.
|
||||
// For x86, `asm!` uses intel syntax by default, but we want to use at&t syntax in the kernel.
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[macro_export]
|
||||
macro_rules! asm {
|
||||
($($asm:expr),* ; $($rest:tt)*) => {
|
||||
::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
|
||||
};
|
||||
}
|
||||
|
||||
/// Wrapper around `asm!` configured for use in the kernel.
|
||||
///
|
||||
/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
|
||||
/// syntax.
|
||||
// For non-x86 arches we just pass through to `asm!`.
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
#[macro_export]
|
||||
macro_rules! asm {
|
||||
($($asm:expr),* ; $($rest:tt)*) => {
|
||||
::core::arch::asm!( $($asm)*, $($rest)* )
|
||||
};
|
||||
}
|
||||
|
49
rust/kernel/tracepoint.rs
Normal file
49
rust/kernel/tracepoint.rs
Normal file
@ -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_branch_unlikely!(
|
||||
$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;
|
@ -1,6 +1,9 @@
|
||||
# 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
|
||||
|
||||
rust_print-y := rust_print_main.o rust_print_events.o
|
||||
|
||||
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs
|
||||
|
8
samples/rust/rust_print_events.c
Normal file
8
samples/rust/rust_print_events.c
Normal file
@ -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>
|
@ -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) }
|
||||
}
|
||||
}
|
@ -248,12 +248,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 = \
|
||||
OBJTREE=$(abspath $(objtree)) \
|
||||
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
|
||||
-Zallow-features=$(rust_allowed_features) \
|
||||
-Zcrate-attr=no_std \
|
||||
@ -303,6 +304,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)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user