Skip to content

Commit bbdc4bc

Browse files
wedsonafDanilo Krummrich
authored andcommitted
rust: add dev_* print macros.
Implement `dev_*` print macros for `device::Device`. They behave like the macros with the same names in C, i.e., they print messages to the kernel ring buffer with the given level, prefixing the messages with corresponding device information. Signed-off-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 7034800 commit bbdc4bc

File tree

2 files changed

+320
-1
lines changed

2 files changed

+320
-1
lines changed

rust/kernel/device.rs

Lines changed: 318 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use crate::{
88
bindings,
99
types::{ARef, Opaque},
1010
};
11-
use core::ptr;
11+
use core::{fmt, ptr};
12+
13+
#[cfg(CONFIG_PRINTK)]
14+
use crate::c_str;
1215

1316
/// A reference-counted device.
1417
///
@@ -82,6 +85,110 @@ impl Device {
8285
// SAFETY: Guaranteed by the safety requirements of the function.
8386
unsafe { &*ptr.cast() }
8487
}
88+
89+
/// Prints an emergency-level message (level 0) prefixed with device information.
90+
///
91+
/// More details are available from [`dev_emerg`].
92+
///
93+
/// [`dev_emerg`]: crate::dev_emerg
94+
pub fn pr_emerg(&self, args: fmt::Arguments<'_>) {
95+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
96+
unsafe { self.printk(bindings::KERN_EMERG, args) };
97+
}
98+
99+
/// Prints an alert-level message (level 1) prefixed with device information.
100+
///
101+
/// More details are available from [`dev_alert`].
102+
///
103+
/// [`dev_alert`]: crate::dev_alert
104+
pub fn pr_alert(&self, args: fmt::Arguments<'_>) {
105+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
106+
unsafe { self.printk(bindings::KERN_ALERT, args) };
107+
}
108+
109+
/// Prints a critical-level message (level 2) prefixed with device information.
110+
///
111+
/// More details are available from [`dev_crit`].
112+
///
113+
/// [`dev_crit`]: crate::dev_crit
114+
pub fn pr_crit(&self, args: fmt::Arguments<'_>) {
115+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
116+
unsafe { self.printk(bindings::KERN_CRIT, args) };
117+
}
118+
119+
/// Prints an error-level message (level 3) prefixed with device information.
120+
///
121+
/// More details are available from [`dev_err`].
122+
///
123+
/// [`dev_err`]: crate::dev_err
124+
pub fn pr_err(&self, args: fmt::Arguments<'_>) {
125+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
126+
unsafe { self.printk(bindings::KERN_ERR, args) };
127+
}
128+
129+
/// Prints a warning-level message (level 4) prefixed with device information.
130+
///
131+
/// More details are available from [`dev_warn`].
132+
///
133+
/// [`dev_warn`]: crate::dev_warn
134+
pub fn pr_warn(&self, args: fmt::Arguments<'_>) {
135+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
136+
unsafe { self.printk(bindings::KERN_WARNING, args) };
137+
}
138+
139+
/// Prints a notice-level message (level 5) prefixed with device information.
140+
///
141+
/// More details are available from [`dev_notice`].
142+
///
143+
/// [`dev_notice`]: crate::dev_notice
144+
pub fn pr_notice(&self, args: fmt::Arguments<'_>) {
145+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
146+
unsafe { self.printk(bindings::KERN_NOTICE, args) };
147+
}
148+
149+
/// Prints an info-level message (level 6) prefixed with device information.
150+
///
151+
/// More details are available from [`dev_info`].
152+
///
153+
/// [`dev_info`]: crate::dev_info
154+
pub fn pr_info(&self, args: fmt::Arguments<'_>) {
155+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
156+
unsafe { self.printk(bindings::KERN_INFO, args) };
157+
}
158+
159+
/// Prints a debug-level message (level 7) prefixed with device information.
160+
///
161+
/// More details are available from [`dev_dbg`].
162+
///
163+
/// [`dev_dbg`]: crate::dev_dbg
164+
pub fn pr_dbg(&self, args: fmt::Arguments<'_>) {
165+
if cfg!(debug_assertions) {
166+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
167+
unsafe { self.printk(bindings::KERN_DEBUG, args) };
168+
}
169+
}
170+
171+
/// Prints the provided message to the console.
172+
///
173+
/// # Safety
174+
///
175+
/// Callers must ensure that `klevel` is null-terminated; in particular, one of the
176+
/// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
177+
#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
178+
unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
179+
// SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.as_raw`
180+
// is valid because `self` is valid. The "%pA" format string expects a pointer to
181+
// `fmt::Arguments`, which is what we're passing as the last argument.
182+
#[cfg(CONFIG_PRINTK)]
183+
unsafe {
184+
bindings::_dev_printk(
185+
klevel as *const _ as *const core::ffi::c_char,
186+
self.as_raw(),
187+
c_str!("%pA").as_char_ptr(),
188+
&msg as *const _ as *const core::ffi::c_void,
189+
)
190+
};
191+
}
85192
}
86193

87194
// SAFETY: Instances of `Device` are always reference-counted.
@@ -103,3 +210,213 @@ unsafe impl Send for Device {}
103210
// SAFETY: `Device` can be shared among threads because all immutable methods are protected by the
104211
// synchronization in `struct device`.
105212
unsafe impl Sync for Device {}
213+
214+
#[doc(hidden)]
215+
#[macro_export]
216+
macro_rules! dev_printk {
217+
($method:ident, $dev:expr, $($f:tt)*) => {
218+
{
219+
($dev).$method(core::format_args!($($f)*));
220+
}
221+
}
222+
}
223+
224+
/// Prints an emergency-level message (level 0) prefixed with device information.
225+
///
226+
/// This level should be used if the system is unusable.
227+
///
228+
/// Equivalent to the kernel's `dev_emerg` macro.
229+
///
230+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
231+
/// [`core::fmt`] and [`alloc::format!`].
232+
///
233+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
234+
///
235+
/// # Examples
236+
///
237+
/// ```
238+
/// # use kernel::device::Device;
239+
///
240+
/// fn example(dev: &Device) {
241+
/// dev_emerg!(dev, "hello {}\n", "there");
242+
/// }
243+
/// ```
244+
#[macro_export]
245+
macro_rules! dev_emerg {
246+
($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
247+
}
248+
249+
/// Prints an alert-level message (level 1) prefixed with device information.
250+
///
251+
/// This level should be used if action must be taken immediately.
252+
///
253+
/// Equivalent to the kernel's `dev_alert` macro.
254+
///
255+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
256+
/// [`core::fmt`] and [`alloc::format!`].
257+
///
258+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
259+
///
260+
/// # Examples
261+
///
262+
/// ```
263+
/// # use kernel::device::Device;
264+
///
265+
/// fn example(dev: &Device) {
266+
/// dev_alert!(dev, "hello {}\n", "there");
267+
/// }
268+
/// ```
269+
#[macro_export]
270+
macro_rules! dev_alert {
271+
($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
272+
}
273+
274+
/// Prints a critical-level message (level 2) prefixed with device information.
275+
///
276+
/// This level should be used in critical conditions.
277+
///
278+
/// Equivalent to the kernel's `dev_crit` macro.
279+
///
280+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
281+
/// [`core::fmt`] and [`alloc::format!`].
282+
///
283+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
284+
///
285+
/// # Examples
286+
///
287+
/// ```
288+
/// # use kernel::device::Device;
289+
///
290+
/// fn example(dev: &Device) {
291+
/// dev_crit!(dev, "hello {}\n", "there");
292+
/// }
293+
/// ```
294+
#[macro_export]
295+
macro_rules! dev_crit {
296+
($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
297+
}
298+
299+
/// Prints an error-level message (level 3) prefixed with device information.
300+
///
301+
/// This level should be used in error conditions.
302+
///
303+
/// Equivalent to the kernel's `dev_err` macro.
304+
///
305+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
306+
/// [`core::fmt`] and [`alloc::format!`].
307+
///
308+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
309+
///
310+
/// # Examples
311+
///
312+
/// ```
313+
/// # use kernel::device::Device;
314+
///
315+
/// fn example(dev: &Device) {
316+
/// dev_err!(dev, "hello {}\n", "there");
317+
/// }
318+
/// ```
319+
#[macro_export]
320+
macro_rules! dev_err {
321+
($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
322+
}
323+
324+
/// Prints a warning-level message (level 4) prefixed with device information.
325+
///
326+
/// This level should be used in warning conditions.
327+
///
328+
/// Equivalent to the kernel's `dev_warn` macro.
329+
///
330+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
331+
/// [`core::fmt`] and [`alloc::format!`].
332+
///
333+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
334+
///
335+
/// # Examples
336+
///
337+
/// ```
338+
/// # use kernel::device::Device;
339+
///
340+
/// fn example(dev: &Device) {
341+
/// dev_warn!(dev, "hello {}\n", "there");
342+
/// }
343+
/// ```
344+
#[macro_export]
345+
macro_rules! dev_warn {
346+
($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
347+
}
348+
349+
/// Prints a notice-level message (level 5) prefixed with device information.
350+
///
351+
/// This level should be used in normal but significant conditions.
352+
///
353+
/// Equivalent to the kernel's `dev_notice` macro.
354+
///
355+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
356+
/// [`core::fmt`] and [`alloc::format!`].
357+
///
358+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
359+
///
360+
/// # Examples
361+
///
362+
/// ```
363+
/// # use kernel::device::Device;
364+
///
365+
/// fn example(dev: &Device) {
366+
/// dev_notice!(dev, "hello {}\n", "there");
367+
/// }
368+
/// ```
369+
#[macro_export]
370+
macro_rules! dev_notice {
371+
($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
372+
}
373+
374+
/// Prints an info-level message (level 6) prefixed with device information.
375+
///
376+
/// This level should be used for informational messages.
377+
///
378+
/// Equivalent to the kernel's `dev_info` macro.
379+
///
380+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
381+
/// [`core::fmt`] and [`alloc::format!`].
382+
///
383+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
384+
///
385+
/// # Examples
386+
///
387+
/// ```
388+
/// # use kernel::device::Device;
389+
///
390+
/// fn example(dev: &Device) {
391+
/// dev_info!(dev, "hello {}\n", "there");
392+
/// }
393+
/// ```
394+
#[macro_export]
395+
macro_rules! dev_info {
396+
($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
397+
}
398+
399+
/// Prints a debug-level message (level 7) prefixed with device information.
400+
///
401+
/// This level should be used for debug messages.
402+
///
403+
/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
404+
///
405+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
406+
/// [`core::fmt`] and [`alloc::format!`].
407+
///
408+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
409+
///
410+
/// # Examples
411+
///
412+
/// ```
413+
/// # use kernel::device::Device;
414+
///
415+
/// fn example(dev: &Device) {
416+
/// dev_dbg!(dev, "hello {}\n", "there");
417+
/// }
418+
/// ```
419+
#[macro_export]
420+
macro_rules! dev_dbg {
421+
($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
422+
}

rust/kernel/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub use super::build_assert;
2727
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
2828
#[doc(no_inline)]
2929
pub use super::dbg;
30+
pub use super::fmt;
31+
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
3032
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
3133

3234
pub use super::{init, pin_init, try_init, try_pin_init};

0 commit comments

Comments
 (0)