brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 508b022 Raw
414 lines · rust
1// SPDX-License-Identifier: GPL-2.02 3//! Printing facilities.4//!5//! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h)6//!7//! Reference: <https://docs.kernel.org/core-api/printk-basics.html>8 9use core::{10    ffi::{c_char, c_void},11    fmt,12};13 14use crate::str::RawFormatter;15 16// Called from `vsprintf` with format specifier `%pA`.17#[no_mangle]18unsafe extern "C" fn rust_fmt_argument(19    buf: *mut c_char,20    end: *mut c_char,21    ptr: *const c_void,22) -> *mut c_char {23    use fmt::Write;24    // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.25    let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };26    let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });27    w.pos().cast()28}29 30/// Format strings.31///32/// Public but hidden since it should only be used from public macros.33#[doc(hidden)]34pub mod format_strings {35    /// The length we copy from the `KERN_*` kernel prefixes.36    const LENGTH_PREFIX: usize = 2;37 38    /// The length of the fixed format strings.39    pub const LENGTH: usize = 10;40 41    /// Generates a fixed format string for the kernel's [`_printk`].42    ///43    /// The format string is always the same for a given level, i.e. for a44    /// given `prefix`, which are the kernel's `KERN_*` constants.45    ///46    /// [`_printk`]: srctree/include/linux/printk.h47    const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] {48        // Ensure the `KERN_*` macros are what we expect.49        assert!(prefix[0] == b'\x01');50        if is_cont {51            assert!(prefix[1] == b'c');52        } else {53            assert!(prefix[1] >= b'0' && prefix[1] <= b'7');54        }55        assert!(prefix[2] == b'\x00');56 57        let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont {58            b"%pA\0\0\0\0\0"59        } else {60            b"%s: %pA\0"61        };62 63        [64            prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5],65            suffix[6], suffix[7],66        ]67    }68 69    // Generate the format strings at compile-time.70    //71    // This avoids the compiler generating the contents on the fly in the stack.72    //73    // Furthermore, `static` instead of `const` is used to share the strings74    // for all the kernel.75    pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);76    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);77    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);78    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);79    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);80    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);81    pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);82    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);83    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);84}85 86/// Prints a message via the kernel's [`_printk`].87///88/// Public but hidden since it should only be used from public macros.89///90/// # Safety91///92/// The format string must be one of the ones in [`format_strings`], and93/// the module name must be null-terminated.94///95/// [`_printk`]: srctree/include/linux/_printk.h96#[doc(hidden)]97#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]98pub unsafe fn call_printk(99    format_string: &[u8; format_strings::LENGTH],100    module_name: &[u8],101    args: fmt::Arguments<'_>,102) {103    // `_printk` does not seem to fail in any path.104    #[cfg(CONFIG_PRINTK)]105    unsafe {106        bindings::_printk(107            format_string.as_ptr() as _,108            module_name.as_ptr(),109            &args as *const _ as *const c_void,110        );111    }112}113 114/// Prints a message via the kernel's [`_printk`] for the `CONT` level.115///116/// Public but hidden since it should only be used from public macros.117///118/// [`_printk`]: srctree/include/linux/printk.h119#[doc(hidden)]120#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]121pub fn call_printk_cont(args: fmt::Arguments<'_>) {122    // `_printk` does not seem to fail in any path.123    //124    // SAFETY: The format string is fixed.125    #[cfg(CONFIG_PRINTK)]126    unsafe {127        bindings::_printk(128            format_strings::CONT.as_ptr() as _,129            &args as *const _ as *const c_void,130        );131    }132}133 134/// Performs formatting and forwards the string to [`call_printk`].135///136/// Public but hidden since it should only be used from public macros.137#[doc(hidden)]138#[cfg(not(testlib))]139#[macro_export]140#[allow(clippy::crate_in_macro_def)]141macro_rules! print_macro (142    // The non-continuation cases (most of them, e.g. `INFO`).143    ($format_string:path, false, $($arg:tt)+) => (144        // To remain sound, `arg`s must be expanded outside the `unsafe` block.145        // Typically one would use a `let` binding for that; however, `format_args!`146        // takes borrows on the arguments, but does not extend the scope of temporaries.147        // Therefore, a `match` expression is used to keep them around, since148        // the scrutinee is kept until the end of the `match`.149        match format_args!($($arg)+) {150            // SAFETY: This hidden macro should only be called by the documented151            // printing macros which ensure the format string is one of the fixed152            // ones. All `__LOG_PREFIX`s are null-terminated as they are generated153            // by the `module!` proc macro or fixed values defined in a kernel154            // crate.155            args => unsafe {156                $crate::print::call_printk(157                    &$format_string,158                    crate::__LOG_PREFIX,159                    args,160                );161            }162        }163    );164 165    // The `CONT` case.166    ($format_string:path, true, $($arg:tt)+) => (167        $crate::print::call_printk_cont(168            format_args!($($arg)+),169        );170    );171);172 173/// Stub for doctests174#[cfg(testlib)]175#[macro_export]176macro_rules! print_macro (177    ($format_string:path, $e:expr, $($arg:tt)+) => (178        ()179    );180);181 182// We could use a macro to generate these macros. However, doing so ends183// up being a bit ugly: it requires the dollar token trick to escape `$` as184// well as playing with the `doc` attribute. Furthermore, they cannot be easily185// imported in the prelude due to [1]. So, for the moment, we just write them186// manually, like in the C side; while keeping most of the logic in another187// macro, i.e. [`print_macro`].188//189// [1]: https://github.com/rust-lang/rust/issues/52234190 191/// Prints an emergency-level message (level 0).192///193/// Use this level if the system is unusable.194///195/// Equivalent to the kernel's [`pr_emerg`] macro.196///197/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and198/// `alloc::format!` for information about the formatting syntax.199///200/// [`pr_emerg`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_emerg201/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html202///203/// # Examples204///205/// ```206/// pr_emerg!("hello {}\n", "there");207/// ```208#[macro_export]209macro_rules! pr_emerg (210    ($($arg:tt)*) => (211        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)212    )213);214 215/// Prints an alert-level message (level 1).216///217/// Use this level if action must be taken immediately.218///219/// Equivalent to the kernel's [`pr_alert`] macro.220///221/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and222/// `alloc::format!` for information about the formatting syntax.223///224/// [`pr_alert`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_alert225/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html226///227/// # Examples228///229/// ```230/// pr_alert!("hello {}\n", "there");231/// ```232#[macro_export]233macro_rules! pr_alert (234    ($($arg:tt)*) => (235        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)236    )237);238 239/// Prints a critical-level message (level 2).240///241/// Use this level for critical conditions.242///243/// Equivalent to the kernel's [`pr_crit`] macro.244///245/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and246/// `alloc::format!` for information about the formatting syntax.247///248/// [`pr_crit`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_crit249/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html250///251/// # Examples252///253/// ```254/// pr_crit!("hello {}\n", "there");255/// ```256#[macro_export]257macro_rules! pr_crit (258    ($($arg:tt)*) => (259        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)260    )261);262 263/// Prints an error-level message (level 3).264///265/// Use this level for error conditions.266///267/// Equivalent to the kernel's [`pr_err`] macro.268///269/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and270/// `alloc::format!` for information about the formatting syntax.271///272/// [`pr_err`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_err273/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html274///275/// # Examples276///277/// ```278/// pr_err!("hello {}\n", "there");279/// ```280#[macro_export]281macro_rules! pr_err (282    ($($arg:tt)*) => (283        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)284    )285);286 287/// Prints a warning-level message (level 4).288///289/// Use this level for warning conditions.290///291/// Equivalent to the kernel's [`pr_warn`] macro.292///293/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and294/// `alloc::format!` for information about the formatting syntax.295///296/// [`pr_warn`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_warn297/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html298///299/// # Examples300///301/// ```302/// pr_warn!("hello {}\n", "there");303/// ```304#[macro_export]305macro_rules! pr_warn (306    ($($arg:tt)*) => (307        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)308    )309);310 311/// Prints a notice-level message (level 5).312///313/// Use this level for normal but significant conditions.314///315/// Equivalent to the kernel's [`pr_notice`] macro.316///317/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and318/// `alloc::format!` for information about the formatting syntax.319///320/// [`pr_notice`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_notice321/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html322///323/// # Examples324///325/// ```326/// pr_notice!("hello {}\n", "there");327/// ```328#[macro_export]329macro_rules! pr_notice (330    ($($arg:tt)*) => (331        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)332    )333);334 335/// Prints an info-level message (level 6).336///337/// Use this level for informational messages.338///339/// Equivalent to the kernel's [`pr_info`] macro.340///341/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and342/// `alloc::format!` for information about the formatting syntax.343///344/// [`pr_info`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_info345/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html346///347/// # Examples348///349/// ```350/// pr_info!("hello {}\n", "there");351/// ```352#[macro_export]353#[doc(alias = "print")]354macro_rules! pr_info (355    ($($arg:tt)*) => (356        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)357    )358);359 360/// Prints a debug-level message (level 7).361///362/// Use this level for debug messages.363///364/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug365/// yet.366///367/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and368/// `alloc::format!` for information about the formatting syntax.369///370/// [`pr_debug`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_debug371/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html372///373/// # Examples374///375/// ```376/// pr_debug!("hello {}\n", "there");377/// ```378#[macro_export]379#[doc(alias = "print")]380macro_rules! pr_debug (381    ($($arg:tt)*) => (382        if cfg!(debug_assertions) {383            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)384        }385    )386);387 388/// Continues a previous log message in the same line.389///390/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).391///392/// Equivalent to the kernel's [`pr_cont`] macro.393///394/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and395/// `alloc::format!` for information about the formatting syntax.396///397/// [`pr_info!`]: crate::pr_info!398/// [`pr_cont`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_cont399/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html400///401/// # Examples402///403/// ```404/// # use kernel::pr_cont;405/// pr_info!("hello");406/// pr_cont!(" {}\n", "there");407/// ```408#[macro_export]409macro_rules! pr_cont (410    ($($arg:tt)*) => (411        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)412    )413);414