diff --git a/drivers/char/rust_example/src/lib.rs b/drivers/char/rust_example/src/lib.rs index e8405f12ce444a..7184212762bd85 100644 --- a/drivers/char/rust_example/src/lib.rs +++ b/drivers/char/rust_example/src/lib.rs @@ -32,7 +32,11 @@ struct RustExample { impl KernelModule for RustExample { fn init() -> KernelResult { println!("Rust Example (init)"); - println!("Am I built-in? {}", !cfg!(MODULE)); + kprintln!( + level: kernel::printk::KERN_DEBUG, + "Am I built-in? {}", + !cfg!(MODULE) + ); println!("Parameters:"); println!(" my_bool: {}", my_bool.read()); println!(" my_i32: {}", my_i32.read()); @@ -45,7 +49,6 @@ impl KernelModule for RustExample { impl Drop for RustExample { fn drop(&mut self) { println!("My message is {}", self.message); - println!("Rust Example (exit)"); + eprintln!("Rust Example (exit)"); } } - diff --git a/rust/kernel/build.rs b/rust/kernel/build.rs index 5a3794fdc99511..543782acbbf622 100644 --- a/rust/kernel/build.rs +++ b/rust/kernel/build.rs @@ -40,7 +40,14 @@ const INCLUDED_VARS: &[&str] = &[ "FS_USERNS_MOUNT", "FS_RENAME_DOES_D_MOVE", "BINDINGS_GFP_KERNEL", + "KERN_EMERG", + "KERN_ALERT", + "KERN_CRIT", + "KERN_ERR", + "KERN_WARNING", + "KERN_NOTICE", "KERN_INFO", + "KERN_DEBUG", "VERIFY_WRITE", "LINUX_VERSION_CODE", "SEEK_SET", diff --git a/rust/kernel/src/prelude.rs b/rust/kernel/src/prelude.rs index 75a5017488a481..f081daa6bd7e22 100644 --- a/rust/kernel/src/prelude.rs +++ b/rust/kernel/src/prelude.rs @@ -2,16 +2,8 @@ //! The `kernel` prelude -pub use alloc::{ - string::String, - borrow::ToOwned, -}; +pub use alloc::{borrow::ToOwned, string::String}; pub use module::module; -pub use super::{ - println, - KernelResult, - KernelModule, -}; - +pub use super::{eprintln, kprintln, println, KernelModule, KernelResult}; diff --git a/rust/kernel/src/printk.rs b/rust/kernel/src/printk.rs index 1a27c034258a36..b65a2f8cfdabe4 100644 --- a/rust/kernel/src/printk.rs +++ b/rust/kernel/src/printk.rs @@ -6,13 +6,18 @@ use core::fmt; use crate::bindings; use crate::c_types::c_int; +pub use crate::bindings::{ + KERN_ALERT, KERN_CRIT, KERN_DEBUG, KERN_EMERG, KERN_ERR, KERN_INFO, KERN_NOTICE, KERN_WARNING, +}; + +const LEVEL_LEN: usize = 3; + #[doc(hidden)] -pub fn printk(s: &[u8]) { +pub fn printk(s: &[u8], level: &'static [u8; LEVEL_LEN]) { // Don't copy the trailing NUL from `KERN_INFO`. - let mut fmt_str = [0; bindings::KERN_INFO.len() - 1 + b"%.*s\0".len()]; - fmt_str[..bindings::KERN_INFO.len() - 1] - .copy_from_slice(&bindings::KERN_INFO[..bindings::KERN_INFO.len() - 1]); - fmt_str[bindings::KERN_INFO.len() - 1..].copy_from_slice(b"%.*s\0"); + let mut fmt_str = [0; LEVEL_LEN - 1 + b"%.*s\0".len()]; + fmt_str[..LEVEL_LEN - 1].copy_from_slice(&level[..LEVEL_LEN - 1]); + fmt_str[LEVEL_LEN - 1..].copy_from_slice(b"%.*s\0"); // TODO: I believe printk never fails unsafe { bindings::printk(fmt_str.as_ptr() as _, s.len() as c_int, s.as_ptr()) }; @@ -50,6 +55,33 @@ impl fmt::Write for LogLineWriter { } } +/// [`kprintln!`] prints to the kernel console with a given level. +/// If no level is given, it will default to `KERN_INFO`. +#[macro_export] +macro_rules! kprintln { + () => ({ + kprintln!(level: $crate::printk::KERN_INFO); + }); + (level: $level:expr) => ({ + $crate::printk::printk("\n".as_bytes(), $level); + }); + ($msg:expr) => ({ + kprintln!(level: $crate::printk::KERN_INFO, $msg); + }); + (level: $level:expr, $msg:expr) => ({ + $crate::printk::printk(concat!($msg, "\n").as_bytes(), $level); + }); + (level: $level:expr, $fmt:expr, $($arg:tt)*) => ({ + use ::core::fmt; + let mut writer = $crate::printk::LogLineWriter::new(); + let _ = fmt::write(&mut writer, format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap(); + $crate::printk::printk(writer.as_bytes(), $crate::printk::KERN_INFO); + }); + ($fmt:expr, $($arg:tt)*) => ({ + kprintln!(level: $crate::printk::KERN_INFO, $fmt, $($arg)*); + }); +} + /// [`println!`] functions the same as it does in `std`, except instead of /// printing to `stdout`, it writes to the kernel console at the `KERN_INFO` /// level. @@ -58,15 +90,30 @@ impl fmt::Write for LogLineWriter { #[macro_export] macro_rules! println { () => ({ - $crate::printk::printk("\n".as_bytes()); + kprintln!(level: $crate::printk::KERN_INFO); }); - ($fmt:expr) => ({ - $crate::printk::printk(concat!($fmt, "\n").as_bytes()); + ($msg:expr) => ({ + kprintln!(level: $crate::printk::KERN_INFO, $msg); }); ($fmt:expr, $($arg:tt)*) => ({ - use ::core::fmt; - let mut writer = $crate::printk::LogLineWriter::new(); - let _ = fmt::write(&mut writer, format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap(); - $crate::printk::printk(writer.as_bytes()); + kprintln!(level: $crate::printk::KERN_INFO, $fmt, $($arg)*); + }); +} + +/// [`eprintln!`] functions the same as it does in `std`, except instead of +/// printing to `stderr`, it writes to the kernel console at the `KERN_ERR` +/// level. +/// +/// [`eprintln!`]: https://doc.rust-lang.org/stable/std/macro.eprintln.html +#[macro_export] +macro_rules! eprintln { + () => ({ + kprintln!(level: $crate::printk::KERN_ERR); + }); + ($msg:expr) => ({ + kprintln!(level: $crate::printk::KERN_ERR, $msg); + }); + ($fmt:expr, $($arg:tt)*) => ({ + kprintln!(level: $crate::printk::KERN_ERR, $msg, $($arg)*); }); }