mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
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 <fujita.tomonori@gmail.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20250502094537.231725-5-fujita.tomonori@gmail.com [ 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 <ojeda@kernel.org>
This commit is contained in:
parent
826230970a
commit
dff64b0727
@ -34,6 +34,9 @@ obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
|
|||||||
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.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
|
always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs
|
||||||
|
ifndef CONFIG_UML
|
||||||
|
always-$(subst y,$(CONFIG_RUST),$(CONFIG_BUG)) += kernel/generated_arch_warn_asm.rs kernel/generated_arch_reachable_asm.rs
|
||||||
|
endif
|
||||||
|
|
||||||
# Avoids running `$(RUSTC)` when it may not be available.
|
# Avoids running `$(RUSTC)` when it may not be available.
|
||||||
ifdef CONFIG_RUST
|
ifdef CONFIG_RUST
|
||||||
@ -540,5 +543,10 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
|
|||||||
ifdef CONFIG_JUMP_LABEL
|
ifdef CONFIG_JUMP_LABEL
|
||||||
$(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs
|
$(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs
|
||||||
endif
|
endif
|
||||||
|
ifndef CONFIG_UML
|
||||||
|
ifdef CONFIG_BUG
|
||||||
|
$(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generated_arch_reachable_asm.rs
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
endif # CONFIG_RUST
|
endif # CONFIG_RUST
|
||||||
|
@ -6,3 +6,8 @@ __noreturn void rust_helper_BUG(void)
|
|||||||
{
|
{
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rust_helper_WARN_ON(bool cond)
|
||||||
|
{
|
||||||
|
return WARN_ON(cond);
|
||||||
|
}
|
||||||
|
2
rust/kernel/.gitignore
vendored
2
rust/kernel/.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
/generated_arch_static_branch_asm.rs
|
/generated_arch_static_branch_asm.rs
|
||||||
|
/generated_arch_warn_asm.rs
|
||||||
|
/generated_arch_reachable_asm.rs
|
||||||
|
126
rust/kernel/bug.rs
Normal file
126
rust/kernel/bug.rs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
// Copyright (C) 2024, 2025 FUJITA Tomonori <fujita.tomonori@gmail.com>
|
||||||
|
|
||||||
|
//! Support for BUG and WARN functionality.
|
||||||
|
//!
|
||||||
|
//! C header: [`include/asm-generic/bug.h`](srctree/include/asm-generic/bug.h)
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
|
||||||
|
#[cfg(CONFIG_DEBUG_BUGVERBOSE)]
|
||||||
|
macro_rules! warn_flags {
|
||||||
|
($flags:expr) => {
|
||||||
|
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
|
||||||
|
const _FILE: &[u8] = file!().as_bytes();
|
||||||
|
// Plus one for null-terminator.
|
||||||
|
static FILE: [u8; _FILE.len() + 1] = {
|
||||||
|
let mut bytes = [0; _FILE.len() + 1];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < _FILE.len() {
|
||||||
|
bytes[i] = _FILE[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - `file`, `line`, `flags`, and `size` are all compile-time constants or
|
||||||
|
// symbols, preventing any invalid memory access.
|
||||||
|
// - The asm block has no side effects and does not modify any registers
|
||||||
|
// or memory. It is purely for embedding metadata into the ELF section.
|
||||||
|
unsafe {
|
||||||
|
$crate::asm!(
|
||||||
|
concat!(
|
||||||
|
"/* {size} */",
|
||||||
|
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
|
||||||
|
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
|
||||||
|
file = sym FILE,
|
||||||
|
line = const line!(),
|
||||||
|
flags = const FLAGS,
|
||||||
|
size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
|
||||||
|
#[cfg(not(CONFIG_DEBUG_BUGVERBOSE))]
|
||||||
|
macro_rules! warn_flags {
|
||||||
|
($flags:expr) => {
|
||||||
|
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - `flags` and `size` are all compile-time constants, preventing
|
||||||
|
// any invalid memory access.
|
||||||
|
// - The asm block has no side effects and does not modify any registers
|
||||||
|
// or memory. It is purely for embedding metadata into the ELF section.
|
||||||
|
unsafe {
|
||||||
|
$crate::asm!(
|
||||||
|
concat!(
|
||||||
|
"/* {size} */",
|
||||||
|
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
|
||||||
|
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
|
||||||
|
flags = const FLAGS,
|
||||||
|
size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(all(CONFIG_BUG, CONFIG_UML))]
|
||||||
|
macro_rules! warn_flags {
|
||||||
|
($flags:expr) => {
|
||||||
|
// SAFETY: It is always safe to call `warn_slowpath_fmt()`
|
||||||
|
// with a valid null-terminated string.
|
||||||
|
unsafe {
|
||||||
|
$crate::bindings::warn_slowpath_fmt(
|
||||||
|
$crate::c_str!(::core::file!()).as_char_ptr(),
|
||||||
|
line!() as $crate::ffi::c_int,
|
||||||
|
$flags as $crate::ffi::c_uint,
|
||||||
|
::core::ptr::null(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))]
|
||||||
|
macro_rules! warn_flags {
|
||||||
|
($flags:expr) => {
|
||||||
|
// SAFETY: It is always safe to call `WARN_ON()`.
|
||||||
|
unsafe { $crate::bindings::WARN_ON(true) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(not(CONFIG_BUG))]
|
||||||
|
macro_rules! warn_flags {
|
||||||
|
($flags:expr) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const fn bugflag_taint(value: u32) -> u32 {
|
||||||
|
value << 8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report a warning if `cond` is true and return the condition's evaluation result.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn_on {
|
||||||
|
($cond:expr) => {{
|
||||||
|
let cond = $cond;
|
||||||
|
if cond {
|
||||||
|
const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN);
|
||||||
|
|
||||||
|
$crate::warn_flags!(WARN_ON_FLAGS);
|
||||||
|
}
|
||||||
|
cond
|
||||||
|
}};
|
||||||
|
}
|
7
rust/kernel/generated_arch_reachable_asm.rs.S
Normal file
7
rust/kernel/generated_arch_reachable_asm.rs.S
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#include <linux/bug.h>
|
||||||
|
|
||||||
|
// Cut here.
|
||||||
|
|
||||||
|
::kernel::concat_literals!(ARCH_WARN_REACHABLE)
|
7
rust/kernel/generated_arch_warn_asm.rs.S
Normal file
7
rust/kernel/generated_arch_warn_asm.rs.S
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#include <linux/bug.h>
|
||||||
|
|
||||||
|
// Cut here.
|
||||||
|
|
||||||
|
::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", "{flags}", "{size}"))
|
@ -57,6 +57,7 @@ pub mod auxiliary;
|
|||||||
pub mod bits;
|
pub mod bits;
|
||||||
#[cfg(CONFIG_BLOCK)]
|
#[cfg(CONFIG_BLOCK)]
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
pub mod bug;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod build_assert;
|
pub mod build_assert;
|
||||||
pub mod clk;
|
pub mod clk;
|
||||||
|
Loading…
Reference in New Issue
Block a user