Message ID | 20250213135759.190006-6-fujita.tomonori@gmail.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | rust: Add bug/warn abstractions | expand |
On Thu, Feb 13, 2025 at 3:01 PM FUJITA Tomonori <fujita.tomonori@gmail.com> wrote: > > Add warn_on and warn_on_once macros. Wrapping the C's WARN_* and BUG_* > macros doesn't work so this uses the assembly code exported by the C > side via ARCH_WARN_ASM macro. Like the static branch code, this > generates the assembly code for rust at compile time by using the C > preprocessor. > > file()! macro doesn't work for the Rust inline assembly in the same > way as __FILE__ for the C inline assembly. So the code to handle a > file name is different from the C assembly code (similar to the > arm64/loongarch assembly). > > Similarly, ARCH_WARN_REACHABLE is also used at compile time to > generate the assembly code; objtool's reachable anotation code. Only > architectures that use objtool (x86 and loongarch) need it. > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> > --- > rust/Makefile | 8 ++ > rust/kernel/.gitignore | 2 + > rust/kernel/bug.rs | 100 ++++++++++++++++++ > rust/kernel/generated_arch_reachable_asm.rs.S | 7 ++ > rust/kernel/generated_arch_warn_asm.rs.S | 7 ++ > rust/kernel/lib.rs | 1 + > 6 files changed, 125 insertions(+) > create mode 100644 rust/kernel/bug.rs > create mode 100644 rust/kernel/generated_arch_reachable_asm.rs.S > create mode 100644 rust/kernel/generated_arch_warn_asm.rs.S > > diff --git a/rust/Makefile b/rust/Makefile > index 8fcfd60447bc..a295b65c43f3 100644 > --- a/rust/Makefile > +++ b/rust/Makefile > @@ -34,6 +34,9 @@ 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 > +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. > ifdef CONFIG_RUST > @@ -481,5 +484,10 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \ > ifdef CONFIG_JUMP_LABEL > $(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs > 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 > diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore > index 6ba39a178f30..f1d7f4225332 100644 > --- a/rust/kernel/.gitignore > +++ b/rust/kernel/.gitignore > @@ -1,3 +1,5 @@ > # SPDX-License-Identifier: GPL-2.0 > > /generated_arch_static_branch_asm.rs > +/generated_arch_warn_asm.rs > +/generated_arch_reachable_asm.rs > \ No newline at end of file > diff --git a/rust/kernel/bug.rs b/rust/kernel/bug.rs > new file mode 100644 > index 000000000000..7ffd9cb1ad75 > --- /dev/null > +++ b/rust/kernel/bug.rs > @@ -0,0 +1,100 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +// Copyright (C) 2024 FUJITA Tomonori > + > +//! 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)))] > +macro_rules! warn_flags { > + ($flags:expr) => { > + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; > + // SAFETY: Just an FFI call. > + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] > + unsafe { > + $crate::asm!(concat!( > + "/* {size} */", > + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", > + "111:\t .string ", "\"", file!(), "\"\n", > + ".popsection\n", It looks like you're doing this so that you can reference the filename with "111b", but could you do this instead: const _FILE: &[u8] = file!().as_bytes(); // Plus one for nul-terminator. static FILE: [u8; 1 + _FILE.len()] = { let mut bytes = [0; 1 + _FILE.len()]; let mut i = 0; while i < _FILE.len() { bytes[i] = _FILE[i]; i += 1; } bytes }; and then use 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!(), ... ); with ::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", "{flags}", "{size}")), That would be a lot simpler to understand than what you are doing. Alice
On Mon, 3 Mar 2025 14:33:39 +0100 Alice Ryhl <aliceryhl@google.com> wrote: >> +#[macro_export] >> +#[doc(hidden)] >> +#[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] >> +macro_rules! warn_flags { >> + ($flags:expr) => { >> + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; >> + // SAFETY: Just an FFI call. >> + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] >> + unsafe { >> + $crate::asm!(concat!( >> + "/* {size} */", >> + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", >> + "111:\t .string ", "\"", file!(), "\"\n", >> + ".popsection\n", > > It looks like you're doing this so that you can reference the filename > with "111b", but could you do this instead: > > const _FILE: &[u8] = file!().as_bytes(); > // Plus one for nul-terminator. > static FILE: [u8; 1 + _FILE.len()] = { > let mut bytes = [0; 1 + _FILE.len()]; > let mut i = 0; > while i < _FILE.len() { > bytes[i] = _FILE[i]; > i += 1; > } > bytes > }; Neat! I will use this in the next version. > and then use > > 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!(), > ... > ); > > with > ::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", > "{flags}", "{size}")), > > That would be a lot simpler to understand than what you are doing. Indeed. Thanks a lot!
On Thu, Feb 13, 2025 at 10:57:59PM +0900, FUJITA Tomonori wrote: > Add warn_on and warn_on_once macros. Wrapping the C's WARN_* and BUG_* > macros doesn't work so this uses the assembly code exported by the C > side via ARCH_WARN_ASM macro. Like the static branch code, this > generates the assembly code for rust at compile time by using the C > preprocessor. > > file()! macro doesn't work for the Rust inline assembly in the same > way as __FILE__ for the C inline assembly. So the code to handle a > file name is different from the C assembly code (similar to the > arm64/loongarch assembly). Nit: Should be file!() not file()!. > diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore > index 6ba39a178f30..f1d7f4225332 100644 > --- a/rust/kernel/.gitignore > +++ b/rust/kernel/.gitignore > @@ -1,3 +1,5 @@ > # SPDX-License-Identifier: GPL-2.0 > > /generated_arch_static_branch_asm.rs > +/generated_arch_warn_asm.rs > +/generated_arch_reachable_asm.rs > \ No newline at end of file There should be a newline. > +++ b/rust/kernel/bug.rs > @@ -0,0 +1,100 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +// Copyright (C) 2024 FUJITA Tomonori 2025? > +#[macro_export] > +#[doc(hidden)] > +#[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] > +macro_rules! warn_flags { > + ($flags:expr) => { > + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; > + // SAFETY: Just an FFI call. > + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] > + unsafe { > + $crate::asm!(concat!( > + "/* {size} */", > + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", > + "111:\t .string ", "\"", file!(), "\"\n", > + ".popsection\n", > + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), > + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); > + line = const line!(), > + flags = const FLAGS, > + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), > + ); > + } > + // SAFETY: Just an FFI call. > + #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] > + 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>(), > + ); > + } I generally prefer to have the cfgs on the macro rather in its expansion. That avoids emitting a lot of code that is not actually used. > +#[doc(hidden)] > +#[macro_export] > +macro_rules! bugflag_taint { > + ($taint:expr) => { > + $taint << 8 > + }; > +} This could just be a const fn. > +/// Report a warning only once. > +#[macro_export] > +macro_rules! warn_on_once { > + ($cond:expr) => { > + if $cond { > + $crate::warn_flags!( > + $crate::bindings::BUGFLAG_ONCE > + | $crate::bugflag_taint!($crate::bindings::TAINT_WARN) Or maybe a constant? const WARN_ON_ONCE_FLAGS: u32 = bindings::BUGFLAG_ONCE | (bindings::TAINT_WARN << 8); $crate::warn_flags!($crate::bug::WARN_ON_ONCE_FLAGS); Alice
On Wed, 5 Mar 2025 08:42:57 +0000 Alice Ryhl <aliceryhl@google.com> wrote: > On Thu, Feb 13, 2025 at 10:57:59PM +0900, FUJITA Tomonori wrote: >> Add warn_on and warn_on_once macros. Wrapping the C's WARN_* and BUG_* >> macros doesn't work so this uses the assembly code exported by the C >> side via ARCH_WARN_ASM macro. Like the static branch code, this >> generates the assembly code for rust at compile time by using the C >> preprocessor. >> >> file()! macro doesn't work for the Rust inline assembly in the same >> way as __FILE__ for the C inline assembly. So the code to handle a >> file name is different from the C assembly code (similar to the >> arm64/loongarch assembly). > > Nit: Should be file!() not file()!. Ops, thanks. Actually, the above comment is obsolete. With your solution in the previous mail, I can remove the asm code for the file name. I'll remove the comment. >> diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore >> index 6ba39a178f30..f1d7f4225332 100644 >> --- a/rust/kernel/.gitignore >> +++ b/rust/kernel/.gitignore >> @@ -1,3 +1,5 @@ >> # SPDX-License-Identifier: GPL-2.0 >> >> /generated_arch_static_branch_asm.rs >> +/generated_arch_warn_asm.rs >> +/generated_arch_reachable_asm.rs >> \ No newline at end of file > > There should be a newline. Ah, I'll fix. >> +++ b/rust/kernel/bug.rs >> @@ -0,0 +1,100 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +// Copyright (C) 2024 FUJITA Tomonori > > 2025? I'll add. >> +#[macro_export] >> +#[doc(hidden)] >> +#[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] >> +macro_rules! warn_flags { >> + ($flags:expr) => { >> + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; >> + // SAFETY: Just an FFI call. >> + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] >> + unsafe { >> + $crate::asm!(concat!( >> + "/* {size} */", >> + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", >> + "111:\t .string ", "\"", file!(), "\"\n", >> + ".popsection\n", >> + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), >> + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); >> + line = const line!(), >> + flags = const FLAGS, >> + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), >> + ); >> + } >> + // SAFETY: Just an FFI call. >> + #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] >> + 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>(), >> + ); >> + } > > I generally prefer to have the cfgs on the macro rather in its > expansion. That avoids emitting a lot of code that is not actually used. You prefer the following? #[cfg(all(CONFIG_BUG, CONFIG_DEBUG_BUGVERBOSE, not(CONFIG_UML)))] macro_rules! warn_flags { ... } #[cfg(all(CONFIG_BUG, not(CONFIG_DEBUG_BUGVERBOSE), not(CONFIG_UML)))] macro_rules! warn_flags { ... } >> +#[doc(hidden)] >> +#[macro_export] >> +macro_rules! bugflag_taint { >> + ($taint:expr) => { >> + $taint << 8 >> + }; >> +} > > This could just be a const fn. Yeah, would a const fn be preferable? >> +/// Report a warning only once. >> +#[macro_export] >> +macro_rules! warn_on_once { >> + ($cond:expr) => { >> + if $cond { >> + $crate::warn_flags!( >> + $crate::bindings::BUGFLAG_ONCE >> + | $crate::bugflag_taint!($crate::bindings::TAINT_WARN) > > Or maybe a constant? > > const WARN_ON_ONCE_FLAGS: u32 = bindings::BUGFLAG_ONCE | (bindings::TAINT_WARN << 8); Ok, but you prefer "<< 8" than using const fn bugflag_taint()? > $crate::warn_flags!($crate::bug::WARN_ON_ONCE_FLAGS);
On Wed, Mar 05, 2025 at 07:24:03PM +0900, FUJITA Tomonori wrote: > On Wed, 5 Mar 2025 08:42:57 +0000 > Alice Ryhl <aliceryhl@google.com> wrote: > > > On Thu, Feb 13, 2025 at 10:57:59PM +0900, FUJITA Tomonori wrote: > >> Add warn_on and warn_on_once macros. Wrapping the C's WARN_* and BUG_* > >> macros doesn't work so this uses the assembly code exported by the C > >> side via ARCH_WARN_ASM macro. Like the static branch code, this > >> generates the assembly code for rust at compile time by using the C > >> preprocessor. > >> > >> file()! macro doesn't work for the Rust inline assembly in the same > >> way as __FILE__ for the C inline assembly. So the code to handle a > >> file name is different from the C assembly code (similar to the > >> arm64/loongarch assembly). > > > > Nit: Should be file!() not file()!. > > Ops, thanks. > > Actually, the above comment is obsolete. With your solution in the > previous mail, I can remove the asm code for the file name. I'll > remove the comment. > > > >> diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore > >> index 6ba39a178f30..f1d7f4225332 100644 > >> --- a/rust/kernel/.gitignore > >> +++ b/rust/kernel/.gitignore > >> @@ -1,3 +1,5 @@ > >> # SPDX-License-Identifier: GPL-2.0 > >> > >> /generated_arch_static_branch_asm.rs > >> +/generated_arch_warn_asm.rs > >> +/generated_arch_reachable_asm.rs > >> \ No newline at end of file > > > > There should be a newline. > > Ah, I'll fix. > > >> +++ b/rust/kernel/bug.rs > >> @@ -0,0 +1,100 @@ > >> +// SPDX-License-Identifier: GPL-2.0 > >> + > >> +// Copyright (C) 2024 FUJITA Tomonori > > > > 2025? > > I'll add. > > >> +#[macro_export] > >> +#[doc(hidden)] > >> +#[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] > >> +macro_rules! warn_flags { > >> + ($flags:expr) => { > >> + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; > >> + // SAFETY: Just an FFI call. > >> + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] > >> + unsafe { > >> + $crate::asm!(concat!( > >> + "/* {size} */", > >> + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", > >> + "111:\t .string ", "\"", file!(), "\"\n", > >> + ".popsection\n", > >> + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), > >> + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); > >> + line = const line!(), > >> + flags = const FLAGS, > >> + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), > >> + ); > >> + } > >> + // SAFETY: Just an FFI call. > >> + #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] > >> + 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>(), > >> + ); > >> + } > > > > I generally prefer to have the cfgs on the macro rather in its > > expansion. That avoids emitting a lot of code that is not actually used. > > You prefer the following? > > #[cfg(all(CONFIG_BUG, CONFIG_DEBUG_BUGVERBOSE, not(CONFIG_UML)))] > macro_rules! warn_flags { > ... > } > > #[cfg(all(CONFIG_BUG, not(CONFIG_DEBUG_BUGVERBOSE), not(CONFIG_UML)))] > macro_rules! warn_flags { > ... > } In this case it probably reads better as #[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] #[cfg(CONFIG_DEBUG_BUGVERBOSE)] macro_rules! warn_flags { ... } #[cfg(all(CONFIG_BUG, not(CONFIG_UML)))] #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] macro_rules! warn_flags { ... } but yes. > >> +#[doc(hidden)] > >> +#[macro_export] > >> +macro_rules! bugflag_taint { > >> + ($taint:expr) => { > >> + $taint << 8 > >> + }; > >> +} > > > > This could just be a const fn. > > Yeah, would a const fn be preferable? Yes, I think a constant or const fn is preferable over a macro whenever possible. > >> +/// Report a warning only once. > >> +#[macro_export] > >> +macro_rules! warn_on_once { > >> + ($cond:expr) => { > >> + if $cond { > >> + $crate::warn_flags!( > >> + $crate::bindings::BUGFLAG_ONCE > >> + | $crate::bugflag_taint!($crate::bindings::TAINT_WARN) > > > > Or maybe a constant? > > > > const WARN_ON_ONCE_FLAGS: u32 = bindings::BUGFLAG_ONCE | (bindings::TAINT_WARN << 8); > > Ok, but you prefer "<< 8" than using const fn bugflag_taint()? I'm also happy with const WARN_ON_ONCE_FLAGS: u32 = bindings::BUGFLAG_ONCE | bugflag_taint(bindings::TAINT_WARN); Up to you. Alice
diff --git a/rust/Makefile b/rust/Makefile index 8fcfd60447bc..a295b65c43f3 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -34,6 +34,9 @@ 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 +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. ifdef CONFIG_RUST @@ -481,5 +484,10 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \ ifdef CONFIG_JUMP_LABEL $(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs 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 diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore index 6ba39a178f30..f1d7f4225332 100644 --- a/rust/kernel/.gitignore +++ b/rust/kernel/.gitignore @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 /generated_arch_static_branch_asm.rs +/generated_arch_warn_asm.rs +/generated_arch_reachable_asm.rs \ No newline at end of file diff --git a/rust/kernel/bug.rs b/rust/kernel/bug.rs new file mode 100644 index 000000000000..7ffd9cb1ad75 --- /dev/null +++ b/rust/kernel/bug.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 FUJITA Tomonori + +//! 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)))] +macro_rules! warn_flags { + ($flags:expr) => { + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; + // SAFETY: Just an FFI call. + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] + unsafe { + $crate::asm!(concat!( + "/* {size} */", + ".pushsection .rodata.str1.1, \"aMS\",@progbits, 1\n", + "111:\t .string ", "\"", file!(), "\"\n", + ".popsection\n", + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); + line = const line!(), + flags = const FLAGS, + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), + ); + } + // SAFETY: Just an FFI call. + #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] + 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: Just an FFI call. + unsafe { + $crate::bindings::warn_slowpath_fmt( + $crate::c_str!(::core::file!()).as_ptr() as *const ::core::ffi::c_char, + line!() as i32, + $flags as u32, + ::core::ptr::null() as *const ::core::ffi::c_char, + ); + } + }; +} + +#[macro_export] +#[doc(hidden)] +#[cfg(not(CONFIG_BUG))] +macro_rules! warn_flags { + ($flags:expr) => {}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! bugflag_taint { + ($taint:expr) => { + $taint << 8 + }; +} + +/// Report a warning only once. +#[macro_export] +macro_rules! warn_on_once { + ($cond:expr) => { + if $cond { + $crate::warn_flags!( + $crate::bindings::BUGFLAG_ONCE + | $crate::bugflag_taint!($crate::bindings::TAINT_WARN) + ); + } + $cond + }; +} + +/// Report a warning. +#[macro_export] +macro_rules! warn_on { + ($cond:expr) => { + if $cond { + $crate::warn_flags!($crate::bugflag_taint!($crate::bindings::TAINT_WARN)); + } + $cond + }; +} diff --git a/rust/kernel/generated_arch_reachable_asm.rs.S b/rust/kernel/generated_arch_reachable_asm.rs.S new file mode 100644 index 000000000000..3886a9ad3a99 --- /dev/null +++ b/rust/kernel/generated_arch_reachable_asm.rs.S @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/bug.h> + +// Cut here. + +::kernel::concat_literals!(ARCH_WARN_REACHABLE) diff --git a/rust/kernel/generated_arch_warn_asm.rs.S b/rust/kernel/generated_arch_warn_asm.rs.S new file mode 100644 index 000000000000..8f239b431aa4 --- /dev/null +++ b/rust/kernel/generated_arch_warn_asm.rs.S @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/bug.h> + +// Cut here. + +::kernel::concat_literals!(ARCH_WARN_ASM("111b", "{line}", "{flags}", "{size}")) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 496ed32b0911..c0720846b249 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -38,6 +38,7 @@ pub mod alloc; #[cfg(CONFIG_BLOCK)] pub mod block; +pub mod bug; #[doc(hidden)] pub mod build_assert; pub mod cred;
Add warn_on and warn_on_once macros. Wrapping the C's WARN_* and BUG_* macros doesn't work so this uses the assembly code exported by the C side via ARCH_WARN_ASM macro. Like the static branch code, this generates the assembly code for rust at compile time by using the C preprocessor. file()! macro doesn't work for the Rust inline assembly in the same way as __FILE__ for the C inline assembly. So the code to handle a file name is different from the C assembly code (similar to the arm64/loongarch assembly). Similarly, ARCH_WARN_REACHABLE is also used at compile time to generate the assembly code; objtool's reachable anotation code. Only architectures that use objtool (x86 and loongarch) need it. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/Makefile | 8 ++ rust/kernel/.gitignore | 2 + rust/kernel/bug.rs | 100 ++++++++++++++++++ rust/kernel/generated_arch_reachable_asm.rs.S | 7 ++ rust/kernel/generated_arch_warn_asm.rs.S | 7 ++ rust/kernel/lib.rs | 1 + 6 files changed, 125 insertions(+) create mode 100644 rust/kernel/bug.rs create mode 100644 rust/kernel/generated_arch_reachable_asm.rs.S create mode 100644 rust/kernel/generated_arch_warn_asm.rs.S