1 // SPDX-License-Identifier: GPL-2.0
2
3 // Copyright (C) 2024, 2025 FUJITA Tomonori <fujita.tomonori@gmail.com>
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)]
bugflag_taint(value: u32) -> u32110 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 }
127