Skip to content

Commit dff64b0

Browse files
fujitaojeda
authored andcommitted
rust: Add warn_on macro
Add warn_on macro, uses the BUG/WARN feature (lib/bug.c) via assembly for x86_64/arm64/riscv. The current Rust code simply wraps BUG() macro but doesn't provide the proper debug information. The BUG/WARN feature can only be used from assembly. This uses the assembly code exported by the C side via ARCH_WARN_ASM macro. To avoid duplicating the assembly code, this approach follows the same strategy as the static branch code: it generates the assembly code for Rust using the C preprocessor at compile time. Similarly, ARCH_WARN_REACHABLE is also used at compile time to generate the assembly code; objtool's reachable annotation code. It's used for only architectures that use objtool. For now, Loongarch and arm just use a wrapper for WARN macro. UML doesn't use the assembly BUG/WARN feature; just wrapping generic BUG/WARN functions implemented in C works. Signed-off-by: FUJITA Tomonori <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Avoid evaluating the condition twice (a good idea in general, but it also matches the C side). Simplify with `as_char_ptr()` to avoid a cast. Cast to `ffi` integer types for `warn_slowpath_fmt`. Avoid cast for `null()`. - Miguel ] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 8262309 commit dff64b0

File tree

7 files changed

+156
-0
lines changed

7 files changed

+156
-0
lines changed

rust/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
3434
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
3535

3636
always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs
37+
ifndef CONFIG_UML
38+
always-$(subst y,$(CONFIG_RUST),$(CONFIG_BUG)) += kernel/generated_arch_warn_asm.rs kernel/generated_arch_reachable_asm.rs
39+
endif
3740

3841
# Avoids running `$(RUSTC)` when it may not be available.
3942
ifdef CONFIG_RUST
@@ -540,5 +543,10 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
540543
ifdef CONFIG_JUMP_LABEL
541544
$(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs
542545
endif
546+
ifndef CONFIG_UML
547+
ifdef CONFIG_BUG
548+
$(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generated_arch_reachable_asm.rs
549+
endif
550+
endif
543551

544552
endif # CONFIG_RUST

rust/helpers/bug.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ __noreturn void rust_helper_BUG(void)
66
{
77
BUG();
88
}
9+
10+
bool rust_helper_WARN_ON(bool cond)
11+
{
12+
return WARN_ON(cond);
13+
}

rust/kernel/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0
22

33
/generated_arch_static_branch_asm.rs
4+
/generated_arch_warn_asm.rs
5+
/generated_arch_reachable_asm.rs

rust/kernel/bug.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
// Copyright (C) 2024, 2025 FUJITA Tomonori <[email protected]>
4+
5+
//! Support for BUG and WARN functionality.
6+
//!
7+
//! C header: [`include/asm-generic/bug.h`](srctree/include/asm-generic/bug.h)
8+
9+
#[macro_export]
10+
#[doc(hidden)]
11+
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
12+
#[cfg(CONFIG_DEBUG_BUGVERBOSE)]
13+
macro_rules! warn_flags {
14+
($flags:expr) => {
15+
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
16+
const _FILE: &[u8] = file!().as_bytes();
17+
// Plus one for null-terminator.
18+
static FILE: [u8; _FILE.len() + 1] = {
19+
let mut bytes = [0; _FILE.len() + 1];
20+
let mut i = 0;
21+
while i < _FILE.len() {
22+
bytes[i] = _FILE[i];
23+
i += 1;
24+
}
25+
bytes
26+
};
27+
28+
// SAFETY:
29+
// - `file`, `line`, `flags`, and `size` are all compile-time constants or
30+
// symbols, preventing any invalid memory access.
31+
// - The asm block has no side effects and does not modify any registers
32+
// or memory. It is purely for embedding metadata into the ELF section.
33+
unsafe {
34+
$crate::asm!(
35+
concat!(
36+
"/* {size} */",
37+
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
38+
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
39+
file = sym FILE,
40+
line = const line!(),
41+
flags = const FLAGS,
42+
size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
43+
);
44+
}
45+
}
46+
}
47+
48+
#[macro_export]
49+
#[doc(hidden)]
50+
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
51+
#[cfg(not(CONFIG_DEBUG_BUGVERBOSE))]
52+
macro_rules! warn_flags {
53+
($flags:expr) => {
54+
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
55+
56+
// SAFETY:
57+
// - `flags` and `size` are all compile-time constants, preventing
58+
// any invalid memory access.
59+
// - The asm block has no side effects and does not modify any registers
60+
// or memory. It is purely for embedding metadata into the ELF section.
61+
unsafe {
62+
$crate::asm!(
63+
concat!(
64+
"/* {size} */",
65+
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
66+
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
67+
flags = const FLAGS,
68+
size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
69+
);
70+
}
71+
}
72+
}
73+
74+
#[macro_export]
75+
#[doc(hidden)]
76+
#[cfg(all(CONFIG_BUG, CONFIG_UML))]
77+
macro_rules! warn_flags {
78+
($flags:expr) => {
79+
// SAFETY: It is always safe to call `warn_slowpath_fmt()`
80+
// with a valid null-terminated string.
81+
unsafe {
82+
$crate::bindings::warn_slowpath_fmt(
83+
$crate::c_str!(::core::file!()).as_char_ptr(),
84+
line!() as $crate::ffi::c_int,
85+
$flags as $crate::ffi::c_uint,
86+
::core::ptr::null(),
87+
);
88+
}
89+
};
90+
}
91+
92+
#[macro_export]
93+
#[doc(hidden)]
94+
#[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))]
95+
macro_rules! warn_flags {
96+
($flags:expr) => {
97+
// SAFETY: It is always safe to call `WARN_ON()`.
98+
unsafe { $crate::bindings::WARN_ON(true) }
99+
};
100+
}
101+
102+
#[macro_export]
103+
#[doc(hidden)]
104+
#[cfg(not(CONFIG_BUG))]
105+
macro_rules! warn_flags {
106+
($flags:expr) => {};
107+
}
108+
109+
#[doc(hidden)]
110+
pub const fn bugflag_taint(value: u32) -> u32 {
111+
value << 8
112+
}
113+
114+
/// Report a warning if `cond` is true and return the condition's evaluation result.
115+
#[macro_export]
116+
macro_rules! warn_on {
117+
($cond:expr) => {{
118+
let cond = $cond;
119+
if cond {
120+
const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN);
121+
122+
$crate::warn_flags!(WARN_ON_FLAGS);
123+
}
124+
cond
125+
}};
126+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#include <linux/bug.h>
4+
5+
// Cut here.
6+
7+
::kernel::concat_literals!(ARCH_WARN_REACHABLE)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#include <linux/bug.h>
4+
5+
// Cut here.
6+
7+
::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", "{flags}", "{size}"))

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub mod auxiliary;
5757
pub mod bits;
5858
#[cfg(CONFIG_BLOCK)]
5959
pub mod block;
60+
pub mod bug;
6061
#[doc(hidden)]
6162
pub mod build_assert;
6263
pub mod clk;

0 commit comments

Comments
 (0)