diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 89bd0ba5abe9bf..850c5e35f24f44 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -166,11 +166,6 @@ jobs: cp samples/rust/rust_module_parameters.rs samples/rust/rust_module_parameters_loadable_default.rs cp samples/rust/rust_module_parameters.rs samples/rust/rust_module_parameters_loadable_custom.rs - sed -i 's:" my_:" built-in default my_:g' samples/rust/rust_module_parameters_builtin_default.rs - sed -i 's:" my_:" built-in custom my_:g' samples/rust/rust_module_parameters_builtin_custom.rs - sed -i 's:" my_:" loadable default my_:g' samples/rust/rust_module_parameters_loadable_default.rs - sed -i 's:" my_:" loadable custom my_:g' samples/rust/rust_module_parameters_loadable_custom.rs - sed -i 's:rust_module_parameters:rust_module_parameters_builtin_default:g' samples/rust/rust_module_parameters_builtin_default.rs sed -i 's:rust_module_parameters:rust_module_parameters_builtin_custom:g' samples/rust/rust_module_parameters_builtin_custom.rs sed -i 's:rust_module_parameters:rust_module_parameters_loadable_default:g' samples/rust/rust_module_parameters_loadable_default.rs @@ -217,43 +212,94 @@ jobs: # Check - run: | - grep '] Rust minimal sample (init)$' qemu-stdout.log - grep '] Rust minimal sample (exit)$' qemu-stdout.log - - grep '] Rust module parameters sample (init)$' qemu-stdout.log - grep '] built-in default my_bool: true$' qemu-stdout.log - grep '] built-in default my_i32: 42$' qemu-stdout.log - grep '] built-in default my_str: default str val$' qemu-stdout.log - grep '] built-in default my_usize: 42$' qemu-stdout.log - grep '] built-in default my_array: \[0, 1]$' qemu-stdout.log - grep '] built-in custom my_bool: false$' qemu-stdout.log - grep '] built-in custom my_i32: 345543$' qemu-stdout.log - grep '] built-in custom my_str: 🦀mod$' qemu-stdout.log - grep '] built-in custom my_usize: 84$' qemu-stdout.log - grep '] built-in custom my_array: \[1, 2, 3]$' qemu-stdout.log - grep '] loadable default my_bool: true$' qemu-stdout.log - grep '] loadable default my_i32: 42$' qemu-stdout.log - grep '] loadable default my_str: default str val$' qemu-stdout.log - grep '] loadable default my_usize: 42$' qemu-stdout.log - grep '] loadable default my_array: \[0, 1]$' qemu-stdout.log - grep '] loadable custom my_bool: false$' qemu-stdout.log - grep '] loadable custom my_i32: 345543$' qemu-stdout.log - grep '] loadable custom my_str: 🦀mod$' qemu-stdout.log - grep '] loadable custom my_usize: 84$' qemu-stdout.log - grep '] loadable custom my_array: \[1, 2, 3]$' qemu-stdout.log - grep '] Rust module parameters sample (exit)$' qemu-stdout.log - - grep '] Rust synchronisation primitives sample (init)$' qemu-stdout.log - grep '] Rust synchronisation primitives sample (exit)$' qemu-stdout.log - - grep '] Rust character device sample (init)$' qemu-stdout.log - grep '] Rust character device sample (exit)$' qemu-stdout.log - - grep '] Rust miscellaneous device sample (init)$' qemu-stdout.log - grep '] Rust miscellaneous device sample (exit)$' qemu-stdout.log - - grep '] Rust stack probing sample (init)$' qemu-stdout.log - grep '] Rust stack probing sample (exit)$' qemu-stdout.log + grep '] rust_minimal: Rust minimal sample (init)$' qemu-stdout.log + grep '] rust_minimal: Rust minimal sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_print: Rust printing macros sample (init)$' qemu-stdout.log + + grep '] rust_print: Emergency message (level 0) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Alert message (level 1) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Critical message (level 2) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Error message (level 3) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Warning message (level 4) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Notice message (level 5) with newline w/o args$' qemu-stdout.log + grep '] rust_print: Info message (level 6) with newline w/o args$' qemu-stdout.log + grep '] rust_print: A line that is continued with newline w/o args$' qemu-stdout.log + + grep '] rust_print: Emergency message (level 0) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Alert message (level 1) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Critical message (level 2) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Error message (level 3) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Warning message (level 4) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Notice message (level 5) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: Info message (level 6) w/o newline w/o args$' qemu-stdout.log + grep '] rust_print: A line that is continued w/o newline w/o args$' qemu-stdout.log + + grep '] rust_print: Emergency message (level 0) with newline with args$' qemu-stdout.log + grep '] rust_print: Alert message (level 1) with newline with args$' qemu-stdout.log + grep '] rust_print: Critical message (level 2) with newline with args$' qemu-stdout.log + grep '] rust_print: Error message (level 3) with newline with args$' qemu-stdout.log + grep '] rust_print: Warning message (level 4) with newline with args$' qemu-stdout.log + grep '] rust_print: Notice message (level 5) with newline with args$' qemu-stdout.log + grep '] rust_print: Info message (level 6) with newline with args$' qemu-stdout.log + grep '] rust_print: A line that is continued with newline with args$' qemu-stdout.log + + grep '] rust_print: Emergency message (level 0) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Alert message (level 1) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Critical message (level 2) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Error message (level 3) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Warning message (level 4) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Notice message (level 5) w/o newline with args$' qemu-stdout.log + grep '] rust_print: Info message (level 6) w/o newline with args$' qemu-stdout.log + grep '] rust_print: A line that is continued w/o newline with args$' qemu-stdout.log + + grep '] rust_print: Rust printing macros sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_module_parameters: Rust module parameters sample (init)$' qemu-stdout.log + + grep '] rust_module_parameters_builtin_default: my_bool: true$' qemu-stdout.log + grep '] rust_module_parameters_builtin_default: my_i32: 42$' qemu-stdout.log + grep '] rust_module_parameters_builtin_default: my_str: default str val$' qemu-stdout.log + grep '] rust_module_parameters_builtin_default: my_usize: 42$' qemu-stdout.log + grep '] rust_module_parameters_builtin_default: my_array: \[0, 1]$' qemu-stdout.log + + grep '] rust_module_parameters_builtin_custom: my_bool: false$' qemu-stdout.log + grep '] rust_module_parameters_builtin_custom: my_i32: 345543$' qemu-stdout.log + grep '] rust_module_parameters_builtin_custom: my_str: 🦀mod$' qemu-stdout.log + grep '] rust_module_parameters_builtin_custom: my_usize: 84$' qemu-stdout.log + grep '] rust_module_parameters_builtin_custom: my_array: \[1, 2, 3]$' qemu-stdout.log + + grep '] rust_module_parameters_loadable_default: my_bool: true$' qemu-stdout.log + grep '] rust_module_parameters_loadable_default: my_i32: 42$' qemu-stdout.log + grep '] rust_module_parameters_loadable_default: my_str: default str val$' qemu-stdout.log + grep '] rust_module_parameters_loadable_default: my_usize: 42$' qemu-stdout.log + grep '] rust_module_parameters_loadable_default: my_array: \[0, 1]$' qemu-stdout.log + + grep '] rust_module_parameters_loadable_custom: my_bool: false$' qemu-stdout.log + grep '] rust_module_parameters_loadable_custom: my_i32: 345543$' qemu-stdout.log + grep '] rust_module_parameters_loadable_custom: my_str: 🦀mod$' qemu-stdout.log + grep '] rust_module_parameters_loadable_custom: my_usize: 84$' qemu-stdout.log + grep '] rust_module_parameters_loadable_custom: my_array: \[1, 2, 3]$' qemu-stdout.log + + grep '] rust_module_parameters: Rust module parameters sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_sync: Rust synchronisation primitives sample (init)$' qemu-stdout.log + grep '] rust_sync: Rust synchronisation primitives sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_chrdev: Rust character device sample (init)$' qemu-stdout.log + grep '] rust_chrdev: Rust character device sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_miscdev: Rust miscellaneous device sample (init)$' qemu-stdout.log + grep '] rust_miscdev: Rust miscellaneous device sample (exit)$' qemu-stdout.log + + - run: | + grep '] rust_stack_probing: Rust stack probing sample (init)$' qemu-stdout.log + grep '] rust_stack_probing: Rust stack probing sample (exit)$' qemu-stdout.log # Report - run: | diff --git a/.github/workflows/kernel-arm64-debug.config b/.github/workflows/kernel-arm64-debug.config index 30fe069751bbbb..983a4f0dab3451 100644 --- a/.github/workflows/kernel-arm64-debug.config +++ b/.github/workflows/kernel-arm64-debug.config @@ -1421,6 +1421,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/kernel-arm64-release.config b/.github/workflows/kernel-arm64-release.config index ba4b6aae3f8ed0..a60446a0703f09 100644 --- a/.github/workflows/kernel-arm64-release.config +++ b/.github/workflows/kernel-arm64-release.config @@ -1339,6 +1339,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/kernel-ppc64le-debug.config b/.github/workflows/kernel-ppc64le-debug.config index 00efc00703b24c..e160b88d25f5a3 100644 --- a/.github/workflows/kernel-ppc64le-debug.config +++ b/.github/workflows/kernel-ppc64le-debug.config @@ -1481,6 +1481,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/kernel-ppc64le-release.config b/.github/workflows/kernel-ppc64le-release.config index b51481ac435a8c..f94190476afe56 100644 --- a/.github/workflows/kernel-ppc64le-release.config +++ b/.github/workflows/kernel-ppc64le-release.config @@ -1443,6 +1443,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/kernel-x86_64-debug.config b/.github/workflows/kernel-x86_64-debug.config index 43e31543bcdfbf..a906d1baab2444 100644 --- a/.github/workflows/kernel-x86_64-debug.config +++ b/.github/workflows/kernel-x86_64-debug.config @@ -1433,6 +1433,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/kernel-x86_64-release.config b/.github/workflows/kernel-x86_64-release.config index aa9f8bb816f031..ff5ce673f1fdf2 100644 --- a/.github/workflows/kernel-x86_64-release.config +++ b/.github/workflows/kernel-x86_64-release.config @@ -1381,6 +1381,7 @@ CONFIG_SAMPLES=y # CONFIG_SAMPLE_WATCHDOG is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m CONFIG_SAMPLE_RUST_SYNC=m CONFIG_SAMPLE_RUST_CHRDEV=m diff --git a/.github/workflows/qemu-init.sh b/.github/workflows/qemu-init.sh index 3a0d66a784242d..5a742b9e733679 100755 --- a/.github/workflows/qemu-init.sh +++ b/.github/workflows/qemu-init.sh @@ -3,6 +3,9 @@ busybox insmod rust_minimal.ko busybox rmmod rust_minimal.ko +busybox insmod rust_print.ko +busybox rmmod rust_print.ko + busybox insmod rust_module_parameters.ko busybox rmmod rust_module_parameters.ko diff --git a/.github/workflows/qemu-initramfs.desc b/.github/workflows/qemu-initramfs.desc index 346084ca832126..ab30716a8beace 100644 --- a/.github/workflows/qemu-initramfs.desc +++ b/.github/workflows/qemu-initramfs.desc @@ -6,6 +6,7 @@ slink /bin/sh /bin/busybox 0755 0 0 file /init .github/workflows/qemu-init.sh 0755 0 0 file /rust_minimal.ko samples/rust/rust_minimal.ko 0755 0 0 +file /rust_print.ko samples/rust/rust_print.ko 0755 0 0 file /rust_module_parameters.ko samples/rust/rust_module_parameters.ko 0755 0 0 file /rust_sync.ko samples/rust/rust_sync.ko 0755 0 0 file /rust_chrdev.ko samples/rust/rust_chrdev.ko 0755 0 0 diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 575a34b88936f9..d13be89530c444 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -410,6 +410,8 @@ static u64 clear_seq; #else #define PREFIX_MAX 32 #endif + +/* Keep in sync with rust/kernel/print.rs */ #define LOG_LINE_MAX (1024 - PREFIX_MAX) #define LOG_LEVEL(v) ((v) & 0x07) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index b49789c227aa34..06f9b559aa0f55 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -17,6 +17,7 @@ alloc_error_handler, const_fn, const_mut_refs, + const_panic, try_reserve )] #![deny(clippy::complexity)] @@ -47,7 +48,7 @@ pub mod miscdev; pub mod module_param; pub mod prelude; -pub mod printk; +pub mod print; pub mod random; mod static_assert; pub mod sync; @@ -152,7 +153,7 @@ fn panic(_info: &PanicInfo) -> ! { /// /// fn test() { /// // This prints `8`. -/// println!("{}", offset_of!(Test, b)); +/// info!("{}", offset_of!(Test, b)); /// } /// ``` #[macro_export] @@ -193,7 +194,7 @@ macro_rules! offset_of { /// let b_ptr = &test.b; /// let test_alias = unsafe { container_of!(b_ptr, Test, b) }; /// // This prints `true`. -/// println!("{}", core::ptr::eq(&test, test_alias)); +/// info!("{}", core::ptr::eq(&test, test_alias)); /// } /// ``` #[macro_export] diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 6ebdab011b3e0a..c692caa55e86ce 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -15,4 +15,9 @@ pub use alloc::{borrow::ToOwned, string::String}; pub use module::module; -pub use super::{println, static_assert, KernelModule, KernelResult}; +pub use super::{alert, cont, crit, emerg, err, info, notice, warn}; +pub use super::{pr_alert, pr_cont, pr_crit, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; + +pub use super::static_assert; + +pub use super::{KernelModule, KernelResult}; diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs new file mode 100644 index 00000000000000..48305937d362dd --- /dev/null +++ b/rust/kernel/print.rs @@ -0,0 +1,709 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Printing facilities. +//! +//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h) +//! +//! Reference: + +use core::cmp; +use core::fmt; + +use crate::bindings; +use crate::c_types::c_int; + +/// Format strings. +/// +/// Public but hidden since it should only be used from public macros. +#[doc(hidden)] +pub mod format_strings { + use crate::bindings; + + /// The length we copy from the `KERN_*` kernel prefixes. + const LENGTH_PREFIX: usize = 2; + + /// The length of the fixed format strings. + pub const LENGTH: usize = 11; + + /// Generates a fixed format string for the kernel's [`printk`]. + /// + /// The format string is always the same for a given level, i.e. for a + /// given `prefix`, which are the kernel's `KERN_*` constants. + /// + /// [`printk`]: ../../../../include/linux/printk.h + const fn generate(is_cont: bool, prefix: &[u8; 3]) -> [u8; LENGTH] { + // Ensure the `KERN_*` macros are what we expect. + assert!(prefix[0] == b'\x01'); + if is_cont { + assert!(prefix[1] == b'c'); + } else { + assert!(prefix[1] >= b'0' && prefix[1] <= b'7'); + } + assert!(prefix[2] == b'\x00'); + + let suffix: &[u8; LENGTH - LENGTH_PREFIX] = if is_cont { + b"%.*s\0\0\0\0\0" + } else { + b"%s: %.*s\0" + }; + + [ + prefix[0], prefix[1], suffix[0], suffix[1], suffix[2], suffix[3], suffix[4], suffix[5], + suffix[6], suffix[7], suffix[8], + ] + } + + // Generate the format strings at compile-time. + // + // This avoids the compiler generating the contents on the fly in the stack. + // + // Furthermore, `static` instead of `const` is used to share the strings + // for all the kernel. + pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG); + pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT); + pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT); + pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR); + pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING); + pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE); + pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO); + pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG); + pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT); +} + +/// Prints a message via the kernel's [`printk`]. +/// +/// Public but hidden since it should only be used from public macros. +/// +/// # Safety +/// +/// The format string must be one of the ones in [`format_strings`], and +/// the module name must be null-terminated. +/// +/// [`printk`]: ../../../../include/linux/printk.h +#[doc(hidden)] +pub unsafe fn call_printk( + format_string: &[u8; format_strings::LENGTH], + module_name: &[u8], + string: &[u8], +) { + // `printk` does not seem to fail in any path. + bindings::printk( + format_string.as_ptr() as _, + module_name.as_ptr(), + string.len() as c_int, + string.as_ptr(), + ); +} + +/// Prints a message via the kernel's [`printk`] for the `CONT` level. +/// +/// Public but hidden since it should only be used from public macros. +/// +/// [`printk`]: ../../../../include/linux/printk.h +#[doc(hidden)] +pub fn call_printk_cont(string: &[u8]) { + // `printk` does not seem to fail in any path. + // + // SAFETY: The format string is fixed. + unsafe { + bindings::printk( + format_strings::CONT.as_ptr() as _, + string.len() as c_int, + string.as_ptr(), + ); + } +} + +/// The maximum size of a log line in the kernel. +/// +/// From `kernel/printk/printk.c`. +const LOG_LINE_MAX: usize = 1024 - 32; + +/// The maximum size of a log line in our side. +/// +/// FIXME: We should be smarter than this, but for the moment, to reduce stack +/// usage, we only allow this much which should work for most purposes. +const LOG_LINE_SIZE: usize = 300; +crate::static_assert!(LOG_LINE_SIZE <= LOG_LINE_MAX); + +/// Public but hidden since it should only be used from public macros. +#[doc(hidden)] +pub struct LogLineWriter { + data: [u8; LOG_LINE_SIZE], + pos: usize, +} + +impl LogLineWriter { + /// Creates a new [`LogLineWriter`]. + pub fn new() -> LogLineWriter { + LogLineWriter { + data: [0u8; LOG_LINE_SIZE], + pos: 0, + } + } + + /// Returns the internal buffer as a byte slice. + pub fn as_bytes(&self) -> &[u8] { + &self.data[..self.pos] + } +} + +impl Default for LogLineWriter { + fn default() -> Self { + Self::new() + } +} + +impl fmt::Write for LogLineWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + let copy_len = cmp::min(LOG_LINE_SIZE - 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(()) + } +} + +/// Helper function for the [`print_macro!`] to reduce stack usage. +/// +/// Public but hidden since it should only be used from public macros. +/// +/// # Safety +/// +/// The format string must be one of the ones in [`format_strings`], and +/// the module name must be null-terminated. +#[doc(hidden)] +pub unsafe fn format_and_call( + format_string: &[u8; format_strings::LENGTH], + module_name: &[u8], + args: fmt::Arguments, +) { + // Careful: this object takes quite a bit of stack. + let mut writer = LogLineWriter::new(); + + match fmt::write(&mut writer, args) { + Ok(_) => { + if CONT { + call_printk_cont(writer.as_bytes()); + } else { + call_printk(format_string, module_name, writer.as_bytes()); + } + } + + Err(_) => { + call_printk( + &format_strings::CRIT, + module_name, + b"Failure to format string.\n", + ); + } + }; +} + +/// Performs formatting and forwards the string to [`call_printk`]. +/// +/// Public but hidden since it should only be used from public macros. +#[doc(hidden)] +#[macro_export] +macro_rules! print_macro ( + // Without extra arguments: no need to format anything. + ($format_string:path, false, $suffix:literal, $fmt:expr) => ( + // SAFETY: This hidden macro should only be called by the documented + // printing macros which ensure the format string is one of the fixed + // ones. All `__MODULE_NAME`s are null-terminated as they are generated + // by the `module!` proc macro. + unsafe { + kernel::print::call_printk( + &$format_string, + crate::__MODULE_NAME, + concat!($fmt, $suffix).as_bytes(), + ); + } + ); + + // Without extra arguments: no need to format anything (`CONT` case). + ($format_string:path, true, $suffix:literal, $fmt:expr) => ( + kernel::print::call_printk_cont( + concat!($fmt, $suffix).as_bytes(), + ); + ); + + // With extra arguments: we need to perform formatting. + ($format_string:path, $cont:literal, $suffix:literal, $fmt:expr, $($arg:tt)*) => ( + // Forwarding the call to a function to perform the formatting + // is needed here to avoid stack overflows in non-optimized builds when + // invoking the printing macros a lot of times in the same function. + // Without it, the compiler reserves one `LogLineWriter` per macro + // invocation, which is a huge type. + // + // We could use an immediately-invoked closure for this, which + // seems to lower even more the stack usage at `opt-level=0` because + // `fmt::Arguments` objects do not pile up. However, that breaks + // the `?` operator if used in one of the arguments. + // + // At `opt-level=2`, the generated code is basically the same for + // all alternatives. + // + // SAFETY: This hidden macro should only be called by the documented + // printing macros which ensure the format string is one of the fixed + // ones. All `__MODULE_NAME`s are null-terminated as they are generated + // by the `module!` proc macro. + unsafe { + kernel::print::format_and_call::<$cont>( + &$format_string, + crate::__MODULE_NAME, + format_args!(concat!($fmt, $suffix), $($arg)*), + ); + } + ); +); + +// We could use a macro to generate these macros. However, doing so ends +// up being a bit ugly: it requires the dollar token trick to escape `$` as +// well as playing with the `doc` attribute. Furthermore, they cannot be easily +// imported in the prelude due to [1]. So, for the moment, we just write them +// manually, like in the C side; while keeping most of the logic in another +// macro, i.e. [`print_macro`]. +// +// [1]: https://github.com/rust-lang/rust/issues/52234 + +/// Prints an emergency-level message (level 0). +/// +/// Use [`emerg!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level if the system is unusable. +/// +/// Equivalent to the kernel's [`pr_emerg`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_emerg!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_emerg ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::EMERG, false, "", $($arg)*) + ) +); + +/// Prints an alert-level message (level 1). +/// +/// Use [`alert!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level if action must be taken immediately. +/// +/// Equivalent to the kernel's [`pr_alert`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_alert!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_alert ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::ALERT, false, "", $($arg)*) + ) +); + +/// Prints a critical-level message (level 2). +/// +/// Use [`crit!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level for critical conditions. +/// +/// Equivalent to the kernel's [`pr_crit`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_crit!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_crit ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::CRIT, false, "", $($arg)*) + ) +); + +/// Prints an error-level message (level 3). +/// +/// Use [`err!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level for error conditions. +/// +/// Equivalent to the kernel's [`pr_err`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_err!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_err ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::ERR, false, "", $($arg)*) + ) +); + +/// Prints a warning-level message (level 4). +/// +/// Use [`warn!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level for warning conditions. +/// +/// Equivalent to the kernel's [`pr_warn`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_warn!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_warn ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::WARNING, false, "", $($arg)*) + ) +); + +/// Prints a notice-level message (level 5). +/// +/// Use [`notice!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level for normal but significant conditions. +/// +/// Equivalent to the kernel's [`pr_notice`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_notice!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +macro_rules! pr_notice ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::NOTICE, false, "", $($arg)*) + ) +); + +/// Prints an info-level message (level 6). +/// +/// Use [`info!`] unless you need to continue the message with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use this level for informational messages. +/// +/// Equivalent to the kernel's [`pr_info`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_info!("hello {} ", "there"); +/// cont!("with arguments"); +/// ``` +#[macro_export] +#[doc(alias = "print")] +macro_rules! pr_info ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::INFO, false, "", $($arg)*) + ) +); + +/// Continues a previous log message in the same line. +/// +/// Use [`cont!`] unless you need to continue the message (again) with [`cont!`] +/// or [`pr_cont!`]. +/// +/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]). +/// +/// Equivalent to the kernel's [`pr_cont`] macro. +/// +/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// pr_info!("hello "); +/// pr_cont!("th"); +/// cont!("ere!"); +/// +/// pr_info!("format "); +/// pr_cont!("{} ", "some"); +/// cont!("{}", "arguments"); +/// ``` +#[macro_export] +macro_rules! pr_cont ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::CONT, true, "", $($arg)*) + ) +); + +/// Prints an emergency-level message, with a newline (level 0). +/// +/// Use this level if the system is unusable. +/// +/// Similar to the kernel's [`pr_emerg`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_emerg`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_emerg +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// emerg!("hello there!"); +/// emerg!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_emerg")] +macro_rules! emerg ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::EMERG, false, "\n", $($arg)*) + ) +); + +/// Prints an alert-level message, with a newline (level 1). +/// +/// Use this level if action must be taken immediately. +/// +/// Similar to the kernel's [`pr_alert`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// alert!("hello there!"); +/// alert!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_alert")] +macro_rules! alert ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::ALERT, false, "\n", $($arg)*) + ) +); + +/// Prints a critical-level message, with a newline (level 2). +/// +/// Use this level for critical conditions. +/// +/// Similar to the kernel's [`pr_crit`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// pr_crit!("hello there!"); +/// pr_crit!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_crit")] +macro_rules! crit ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::CRIT, false, "\n", $($arg)*) + ) +); + +/// Prints an error-level message, with a newline (level 3). +/// +/// Use this level for error conditions. +/// +/// Similar to the kernel's [`pr_err`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// err!("hello there!"); +/// err!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_err")] +macro_rules! err ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::ERR, false, "\n", $($arg)*) + ) +); + +/// Prints a warning-level message, with a newline (level 4). +/// +/// Use this level for warning conditions. +/// +/// Similar to the kernel's [`pr_warn`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// warn!("hello there!"); +/// warn!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_warn")] +macro_rules! warn ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::WARNING, false, "\n", $($arg)*) + ) +); + +/// Prints a notice-level message, with a newline (level 5). +/// +/// Use this level for normal but significant conditions. +/// +/// Similar to the kernel's [`pr_notice`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// notice!("hello there!"); +/// notice!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_notice")] +macro_rules! notice ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::NOTICE, false, "\n", $($arg)*) + ) +); + +/// Prints an info-level message, with a newline (level 6). +/// +/// Use this level for informational messages. +/// +/// Similar to the kernel's [`pr_info`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_info`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_info +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// info!("hello there!"); +/// info!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[doc(alias = "pr_info")] +#[doc(alias = "println")] +macro_rules! info ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::INFO, false, "\n", $($arg)*) + ) +); + +/// Continues a previous log message in the same line, with a newline. +/// +/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]). +/// +/// Similar to the kernel's [`pr_cont`] macro. +/// +/// Mimics the interface of [`std::println!`]. See [`core::fmt`] and +/// [`alloc::format!`] for information about the formatting syntax. +/// +/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont +/// [`std::println!`]: https://doc.rust-lang.org/std/macro.println.html +/// +/// # Examples +/// +/// ``` +/// pr_info!("hello "); +/// cont!("there!"); +/// +/// pr_info!("format {}", "some"); +/// cont!(" {}", "arguments"); +/// ``` +#[macro_export] +#[doc(alias = "pr_cont")] +macro_rules! cont ( + ($($arg:tt)*) => ( + $crate::print_macro!($crate::print::format_strings::CONT, true, "\n", $($arg)*) + ) +); diff --git a/rust/kernel/printk.rs b/rust/kernel/printk.rs deleted file mode 100644 index aef05c2c06e1fa..00000000000000 --- a/rust/kernel/printk.rs +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Printing facilities. -//! -//! C header: [`include/linux/printk.h`](../../../../include/linux/printk.h) -//! -//! Reference: - -use core::cmp; -use core::fmt; - -use crate::bindings; -use crate::c_types::c_int; - -#[doc(hidden)] -pub fn printk(s: &[u8]) { - // Do not 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, -} - -impl LogLineWriter { - /// Creates a new [`LogLineWriter`]. - pub fn new() -> LogLineWriter { - LogLineWriter { - data: [0u8; LOG_LINE_MAX], - pos: 0, - } - } - - /// Returns the internal buffer as a byte slice. - pub fn as_bytes(&self) -> &[u8] { - &self.data[..self.pos] - } -} - -impl Default for LogLineWriter { - fn default() -> Self { - Self::new() - } -} - -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(()) - } -} - -/// Prints to the kernel console at `KERN_INFO` level. -/// -/// Mimics the interface of [`std::println!`]. -/// -/// [`std::println!`]: https://doc.rust-lang.org/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()); - }); -} diff --git a/rust/kernel/sync/mod.rs b/rust/kernel/sync/mod.rs index 59fdad84d464a1..625c22600e19c6 100644 --- a/rust/kernel/sync/mod.rs +++ b/rust/kernel/sync/mod.rs @@ -13,7 +13,7 @@ //! let data = alloc::sync::Arc::pin(unsafe { Mutex::new(0) }); //! mutex_init!(data.as_ref(), "test::data"); //! *data.lock() = 10; -//! kernel::println!("{}", *data.lock()); +//! info!("{}", *data.lock()); //! } //! ``` diff --git a/rust/module.rs b/rust/module.rs index d87c0d2433f9e3..fd20c23aa69d8a 100644 --- a/rust/module.rs +++ b/rust/module.rs @@ -355,11 +355,11 @@ fn generated_array_ops_name(vals: &str, max_length: usize) -> String { /// // taken to read the parameter: /// { /// let lock = THIS_MODULE.kernel_param_lock(); -/// println!("i32 param is: {}", writeable_i32.read(&lock)); +/// info!("i32 param is: {}", writeable_i32.read(&lock)); /// } /// // If the parameter is read only, it can be read without locking /// // the kernel parameters: -/// println!("i32 param is: {}", my_i32.read()); +/// info!("i32 param is: {}", my_i32.read()); /// Ok(MyKernelModule) /// } /// } @@ -584,6 +584,11 @@ pub fn module(ts: TokenStream) -> TokenStream { format!( " + /// The module name. + /// + /// Used by the printing macros, e.g. [`info!`]. + const __MODULE_NAME: &[u8] = b\"{name}\\0\"; + static mut __MOD: Option<{type_}> = None; // SAFETY: `__this_module` is constructed by the kernel at load time and will not be freed until the module is unloaded. diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 6aee6ff6765ac4..5260507d2a66ba 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -20,6 +20,16 @@ config SAMPLE_RUST_MINIMAL If unsure, say N. +config SAMPLE_RUST_PRINT + tristate "Printing macros" + help + This option builds the Rust printing macros sample. + + To compile this as a module, choose M here: + the module will be called rust_print. + + If unsure, say N. + config SAMPLE_RUST_MODULE_PARAMETERS tristate "Module parameters" help diff --git a/samples/rust/Makefile b/samples/rust/Makefile index fceefb5a1e1574..47bf362c1e6ca9 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o +obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o obj-$(CONFIG_SAMPLE_RUST_MODULE_PARAMETERS) += rust_module_parameters.o obj-$(CONFIG_SAMPLE_RUST_SYNC) += rust_sync.o obj-$(CONFIG_SAMPLE_RUST_CHRDEV) += rust_chrdev.o diff --git a/samples/rust/rust_chrdev.rs b/samples/rust/rust_chrdev.rs index 6b51652f409fc3..c98e209c3a94e2 100644 --- a/samples/rust/rust_chrdev.rs +++ b/samples/rust/rust_chrdev.rs @@ -28,7 +28,7 @@ struct RustFile; impl FileOpener<()> for RustFile { fn open(_ctx: &()) -> KernelResult { - println!("rust file was opened!"); + info!("rust file was opened!"); Ok(Box::try_new(Self)?) } } @@ -45,7 +45,7 @@ struct RustChrdev { impl KernelModule for RustChrdev { fn init() -> KernelResult { - println!("Rust character device sample (init)"); + info!("Rust character device sample (init)"); let mut chrdev_reg = chrdev::Registration::new_pinned(cstr!("rust_chrdev"), 0, &THIS_MODULE)?; @@ -62,6 +62,6 @@ impl KernelModule for RustChrdev { impl Drop for RustChrdev { fn drop(&mut self) { - println!("Rust character device sample (exit)"); + info!("Rust character device sample (exit)"); } } diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index 2b86c8b1412afc..f919328d82e94a 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -24,8 +24,8 @@ struct RustMinimal { impl KernelModule for RustMinimal { fn init() -> KernelResult { - println!("Rust minimal sample (init)"); - println!("Am I built-in? {}", !cfg!(MODULE)); + info!("Rust minimal sample (init)"); + info!("Am I built-in? {}", !cfg!(MODULE)); Ok(RustMinimal { message: "on the heap!".to_owned(), @@ -35,7 +35,7 @@ impl KernelModule for RustMinimal { impl Drop for RustMinimal { fn drop(&mut self) { - println!("My message is {}", self.message); - println!("Rust minimal sample (exit)"); + info!("My message is {}", self.message); + info!("Rust minimal sample (exit)"); } } diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs index 6bdc280fc980b8..45f71ce0095053 100644 --- a/samples/rust/rust_miscdev.rs +++ b/samples/rust/rust_miscdev.rs @@ -129,7 +129,7 @@ struct RustMiscdev { impl KernelModule for RustMiscdev { fn init() -> KernelResult { - println!("Rust miscellaneous device sample (init)"); + info!("Rust miscellaneous device sample (init)"); let state = SharedState::try_new()?; @@ -141,6 +141,6 @@ impl KernelModule for RustMiscdev { impl Drop for RustMiscdev { fn drop(&mut self) { - println!("Rust miscellaneous device sample (exit)"); + info!("Rust miscellaneous device sample (exit)"); } } diff --git a/samples/rust/rust_module_parameters.rs b/samples/rust/rust_module_parameters.rs index feb71ee8ea4409..a9d442f599792f 100644 --- a/samples/rust/rust_module_parameters.rs +++ b/samples/rust/rust_module_parameters.rs @@ -47,19 +47,19 @@ struct RustModuleParameters; impl KernelModule for RustModuleParameters { fn init() -> KernelResult { - println!("Rust module parameters sample (init)"); + info!("Rust module parameters sample (init)"); { let lock = THIS_MODULE.kernel_param_lock(); - println!("Parameters:"); - println!(" my_bool: {}", my_bool.read()); - println!(" my_i32: {}", my_i32.read(&lock)); - println!( + info!("Parameters:"); + info!(" my_bool: {}", my_bool.read()); + info!(" my_i32: {}", my_i32.read(&lock)); + info!( " my_str: {}", core::str::from_utf8(my_str.read(&lock))? ); - println!(" my_usize: {}", my_usize.read(&lock)); - println!(" my_array: {:?}", my_array.read()); + info!(" my_usize: {}", my_usize.read(&lock)); + info!(" my_array: {:?}", my_array.read()); } Ok(RustModuleParameters) @@ -68,6 +68,6 @@ impl KernelModule for RustModuleParameters { impl Drop for RustModuleParameters { fn drop(&mut self) { - println!("Rust module parameters sample (exit)"); + info!("Rust module parameters sample (exit)"); } } diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs new file mode 100644 index 00000000000000..9f11e8722df6c5 --- /dev/null +++ b/samples/rust/rust_print.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust printing macros sample + +#![no_std] +#![feature(allocator_api, global_asm)] + +use kernel::prelude::*; + +module! { + type: RustPrint, + name: b"rust_print", + author: b"Rust for Linux Contributors", + description: b"Rust printing macros sample", + license: b"GPL v2", + params: { + }, +} + +struct RustPrint; + +impl KernelModule for RustPrint { + fn init() -> KernelResult { + info!("Rust printing macros sample (init)"); + + emerg!("Emergency message (level 0) with newline w/o args"); + alert!("Alert message (level 1) with newline w/o args"); + crit!("Critical message (level 2) with newline w/o args"); + err!("Error message (level 3) with newline w/o args"); + warn!("Warning message (level 4) with newline w/o args"); + notice!("Notice message (level 5) with newline w/o args"); + info!("Info message (level 6) with newline w/o args"); + + pr_info!("A line that"); + pr_cont!(" is continued"); + cont!(" with newline w/o args"); + + pr_emerg!("Emergency message (level 0) w/o newline w/o args\n"); + pr_alert!("Alert message (level 1) w/o newline w/o args\n"); + pr_crit!("Critical message (level 2) w/o newline w/o args\n"); + pr_err!("Error message (level 3) w/o newline w/o args\n"); + pr_warn!("Warning message (level 4) w/o newline w/o args\n"); + pr_notice!("Notice message (level 5) w/o newline w/o args\n"); + pr_info!("Info message (level 6) w/o newline w/o args\n"); + + pr_info!("A line that"); + pr_cont!(" is continued"); + pr_cont!(" w/o newline w/o args\n"); + + emerg!( + "{} message (level {}) with newline with args", + "Emergency", + 0 + ); + alert!("{} message (level {}) with newline with args", "Alert", 1); + crit!( + "{} message (level {}) with newline with args", + "Critical", + 2 + ); + err!("{} message (level {}) with newline with args", "Error", 3); + warn!("{} message (level {}) with newline with args", "Warning", 4); + notice!("{} message (level {}) with newline with args", "Notice", 5); + info!("{} message (level {}) with newline with args", "Info", 6); + + pr_info!("A {} that", "line"); + pr_cont!(" is {}", "continued"); + cont!(" with {} with args", "newline"); + + pr_emerg!( + "{} message (level {}) w/o newline with args\n", + "Emergency", + 0 + ); + pr_alert!("{} message (level {}) w/o newline with args\n", "Alert", 1); + pr_crit!( + "{} message (level {}) w/o newline with args\n", + "Critical", + 2 + ); + pr_err!("{} message (level {}) w/o newline with args\n", "Error", 3); + pr_warn!( + "{} message (level {}) w/o newline with args\n", + "Warning", + 4 + ); + pr_notice!("{} message (level {}) w/o newline with args\n", "Notice", 5); + pr_info!("{} message (level {}) w/o newline with args\n", "Info", 6); + + pr_info!("A {} that", "line"); + pr_cont!(" is {}", "continued"); + pr_cont!(" w/o {} with args\n", "newline"); + + Ok(RustPrint) + } +} + +impl Drop for RustPrint { + fn drop(&mut self) { + info!("Rust printing macros sample (exit)"); + } +} diff --git a/samples/rust/rust_stack_probing.rs b/samples/rust/rust_stack_probing.rs index 3d5608c0fb73c7..2f6fe2c3aece9e 100644 --- a/samples/rust/rust_stack_probing.rs +++ b/samples/rust/rust_stack_probing.rs @@ -22,14 +22,14 @@ struct RustStackProbing; impl KernelModule for RustStackProbing { fn init() -> KernelResult { - println!("Rust stack probing sample (init)"); + info!("Rust stack probing sample (init)"); // Including this large variable on the stack will trigger // stack probing on the supported archs. // This will verify that stack probing does not lead to // any errors if we need to link `__rust_probestack`. let x: [u64; 514] = core::hint::black_box([5; 514]); - println!("Large array has length: {}", x.len()); + info!("Large array has length: {}", x.len()); Ok(RustStackProbing) } @@ -37,6 +37,6 @@ impl KernelModule for RustStackProbing { impl Drop for RustStackProbing { fn drop(&mut self) { - println!("Rust stack probing sample (exit)"); + info!("Rust stack probing sample (exit)"); } } diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs index 8f72c411de2b94..26dbf05bcf34dc 100644 --- a/samples/rust/rust_sync.rs +++ b/samples/rust/rust_sync.rs @@ -28,7 +28,7 @@ struct RustSync; impl KernelModule for RustSync { fn init() -> KernelResult { - println!("Rust synchronisation primitives sample (init)"); + info!("Rust synchronisation primitives sample (init)"); // Test mutexes. { @@ -36,7 +36,7 @@ impl KernelModule for RustSync { let data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?); mutex_init!(data.as_ref(), "RustSync::init::data1"); *data.lock() = 10; - println!("Value: {}", *data.lock()); + info!("Value: {}", *data.lock()); // SAFETY: `init` is called below. let cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?); @@ -58,7 +58,7 @@ impl KernelModule for RustSync { let data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?); spinlock_init!(data.as_ref(), "RustSync::init::data2"); *data.lock() = 10; - println!("Value: {}", *data.lock()); + info!("Value: {}", *data.lock()); // SAFETY: `init` is called below. let cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?); @@ -80,6 +80,6 @@ impl KernelModule for RustSync { impl Drop for RustSync { fn drop(&mut self) { - println!("Rust synchronisation primitives sample (exit)"); + info!("Rust synchronisation primitives sample (exit)"); } }