diff options
Diffstat (limited to 'rust/kernel/src/printk.rs')
-rw-r--r-- | rust/kernel/src/printk.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/rust/kernel/src/printk.rs b/rust/kernel/src/printk.rs new file mode 100644 index 000000000000..1a27c034258a --- /dev/null +++ b/rust/kernel/src/printk.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 + +use core::cmp; +use core::fmt; + +use crate::bindings; +use crate::c_types::c_int; + +#[doc(hidden)] +pub fn printk(s: &[u8]) { + // 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"); + + // TODO: I believe printk never fails + unsafe { bindings::printk(fmt_str.as_ptr() as _, s.len() as c_int, s.as_ptr()) }; +} + +// From kernel/print/printk.c +const LOG_LINE_MAX: usize = 1024 - 32; + +#[doc(hidden)] +pub struct LogLineWriter { + data: [u8; LOG_LINE_MAX], + pos: usize, +} + +#[allow(clippy::new_without_default)] +impl LogLineWriter { + pub fn new() -> LogLineWriter { + LogLineWriter { + data: [0u8; LOG_LINE_MAX], + pos: 0, + } + } + + pub fn as_bytes(&self) -> &[u8] { + &self.data[..self.pos] + } +} + +impl fmt::Write for LogLineWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + let copy_len = cmp::min(LOG_LINE_MAX - self.pos, s.as_bytes().len()); + self.data[self.pos..self.pos + copy_len].copy_from_slice(&s.as_bytes()[..copy_len]); + self.pos += copy_len; + Ok(()) + } +} + +/// [`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. +/// +/// [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html +#[macro_export] +macro_rules! println { + () => ({ + $crate::printk::printk("\n".as_bytes()); + }); + ($fmt:expr) => ({ + $crate::printk::printk(concat!($fmt, "\n").as_bytes()); + }); + ($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()); + }); +} |