Skip to content

Commit 426247f

Browse files
committed
rust: add dev_* print macros.
It behaves like the macros with the same names in C, i.e., it prints messages to the console with the given level, and prefixes the message with device information. Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
1 parent 68c9ac5 commit 426247f

File tree

2 files changed

+327
-2
lines changed

2 files changed

+327
-2
lines changed

rust/kernel/device.rs

Lines changed: 323 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
use crate::{clk::Clk, error::from_kernel_err_ptr};
99

1010
use crate::{
11-
bindings,
11+
bindings, c_str, c_types,
1212
revocable::{Revocable, RevocableGuard},
1313
str::CStr,
1414
sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
1515
Result,
1616
};
1717
use core::{
18+
fmt,
1819
ops::{Deref, DerefMut},
1920
pin::Pin,
2021
};
@@ -64,6 +65,92 @@ pub unsafe trait RawDevice {
6465
// SAFETY: clock is initialized with valid pointer returned from `bindings::clk_get` call.
6566
unsafe { Ok(Clk::new(clk_ptr)) }
6667
}
68+
69+
/// Prints an emergency-level message (level 0) prefixed with device information.
70+
///
71+
/// More details are available from [`dev_emerg`].
72+
fn pr_emerg(&self, args: fmt::Arguments<'_>) {
73+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
74+
unsafe { self.printk(bindings::KERN_EMERG, args) };
75+
}
76+
77+
/// Prints an alert-level message (level 1) prefixed with device information.
78+
///
79+
/// More details are available from [`dev_alert`].
80+
fn pr_alert(&self, args: fmt::Arguments<'_>) {
81+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
82+
unsafe { self.printk(bindings::KERN_ALERT, args) };
83+
}
84+
85+
/// Prints a critical-level message (level 2) prefixed with device information.
86+
///
87+
/// More details are available from [`dev_crit`].
88+
fn pr_crit(&self, args: fmt::Arguments<'_>) {
89+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
90+
unsafe { self.printk(bindings::KERN_CRIT, args) };
91+
}
92+
93+
/// Prints an error-level message (level 3) prefixed with device information.
94+
///
95+
/// More details are available from [`dev_err`].
96+
fn pr_err(&self, args: fmt::Arguments<'_>) {
97+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
98+
unsafe { self.printk(bindings::KERN_ERR, args) };
99+
}
100+
101+
/// Prints a warning-level message (level 4) prefixed with device information.
102+
///
103+
/// More details are available from [`dev_warn`].
104+
fn pr_warn(&self, args: fmt::Arguments<'_>) {
105+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
106+
unsafe { self.printk(bindings::KERN_WARNING, args) };
107+
}
108+
109+
/// Prints a notice-level message (level 5) prefixed with device information.
110+
///
111+
/// More details are available from [`dev_notice`].
112+
fn pr_notice(&self, args: fmt::Arguments<'_>) {
113+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
114+
unsafe { self.printk(bindings::KERN_NOTICE, args) };
115+
}
116+
117+
/// Prints an info-level message (level 6) prefixed with device information.
118+
///
119+
/// More details are available from [`dev_info`].
120+
fn pr_info(&self, args: fmt::Arguments<'_>) {
121+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
122+
unsafe { self.printk(bindings::KERN_INFO, args) };
123+
}
124+
125+
/// Prints a debug-level message (level 7) prefixed with device information.
126+
///
127+
/// More details are available from [`dev_dbg`].
128+
fn pr_dbg(&self, args: fmt::Arguments<'_>) {
129+
if cfg!(debug_assertions) {
130+
// SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
131+
unsafe { self.printk(bindings::KERN_DEBUG, args) };
132+
}
133+
}
134+
135+
/// Prints the provided message to the console.
136+
///
137+
/// # Safety
138+
///
139+
/// Callers must ensure that `klevel` is null-terminated; in particular, one of the
140+
/// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc.
141+
unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
142+
// SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
143+
// is valid because `self` is valid. The "%pA" format string expects a pointer to
144+
// `fmt::Arguments`, which is what we're passing as the last argument.
145+
unsafe {
146+
bindings::_dev_printk(
147+
klevel as *const _ as *const c_types::c_char,
148+
self.raw_device(),
149+
c_str!("%pA").as_char_ptr(),
150+
&msg as *const _ as *const c_types::c_void,
151+
)
152+
};
153+
}
67154
}
68155

69156
/// A ref-counted device.
@@ -76,6 +163,13 @@ pub struct Device {
76163
pub(crate) ptr: *mut bindings::device,
77164
}
78165

166+
// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
167+
unsafe impl Send for Device {}
168+
169+
// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
170+
// from any thread.
171+
unsafe impl Sync for Device {}
172+
79173
impl Device {
80174
/// Creates a new device instance.
81175
///
@@ -98,6 +192,13 @@ impl Device {
98192
}
99193
}
100194

195+
// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
196+
unsafe impl RawDevice for Device {
197+
fn raw_device(&self) -> *mut bindings::device {
198+
self.ptr
199+
}
200+
}
201+
101202
impl Drop for Device {
102203
fn drop(&mut self) {
103204
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
@@ -225,3 +326,224 @@ impl<T, U, V> DerefMut for Data<T, U, V> {
225326
&mut self.general
226327
}
227328
}
329+
330+
#[doc(hidden)]
331+
#[macro_export]
332+
macro_rules! dev_printk {
333+
($method:ident, $dev:expr, $($f:tt)*) => {
334+
{
335+
// We have an explicity `use` statement here so that callers of this macro are not
336+
// required to explicitly use the `RawDevice` trait to use its functions.
337+
use $crate::device::RawDevice;
338+
($dev).$method(core::format_args!($($f)*));
339+
}
340+
}
341+
}
342+
343+
/// Prints an emergency-level message (level 0) prefixed with device information.
344+
///
345+
/// This level should be used if the system is unusable.
346+
///
347+
/// Equivalent to the kernel's `dev_emerg` macro.
348+
///
349+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
350+
/// [`core::fmt`] and [`alloc::format!`].
351+
///
352+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
353+
///
354+
/// # Examples
355+
///
356+
/// ```
357+
/// # use kernel::prelude::*;
358+
/// # use kernel::device::Device;
359+
///
360+
/// fn example(dev: &Device) {
361+
/// dev_emerg!(dev, "hello {}\n", "there");
362+
/// }
363+
/// ```
364+
#[macro_export]
365+
macro_rules! dev_emerg {
366+
($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); }
367+
}
368+
369+
/// Prints an alert-level message (level 1) prefixed with device information.
370+
///
371+
/// This level should be used if action must be taken immediately.
372+
///
373+
/// Equivalent to the kernel's `dev_alert` macro.
374+
///
375+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
376+
/// [`core::fmt`] and [`alloc::format!`].
377+
///
378+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
379+
///
380+
/// # Examples
381+
///
382+
/// ```
383+
/// # use kernel::prelude::*;
384+
/// # use kernel::device::Device;
385+
///
386+
/// fn example(dev: &Device) {
387+
/// dev_alert!(dev, "hello {}\n", "there");
388+
/// }
389+
/// ```
390+
#[macro_export]
391+
macro_rules! dev_alert {
392+
($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); }
393+
}
394+
395+
/// Prints a critical-level message (level 2) prefixed with device information.
396+
///
397+
/// This level should be used in critical conditions.
398+
///
399+
/// Equivalent to the kernel's `dev_crit` macro.
400+
///
401+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
402+
/// [`core::fmt`] and [`alloc::format!`].
403+
///
404+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
405+
///
406+
/// # Examples
407+
///
408+
/// ```
409+
/// # use kernel::prelude::*;
410+
/// # use kernel::device::Device;
411+
///
412+
/// fn example(dev: &Device) {
413+
/// dev_crit!(dev, "hello {}\n", "there");
414+
/// }
415+
/// ```
416+
#[macro_export]
417+
macro_rules! dev_crit {
418+
($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); }
419+
}
420+
421+
/// Prints an error-level message (level 3) prefixed with device information.
422+
///
423+
/// This level should be used in error conditions.
424+
///
425+
/// Equivalent to the kernel's `dev_err` macro.
426+
///
427+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
428+
/// [`core::fmt`] and [`alloc::format!`].
429+
///
430+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
431+
///
432+
/// # Examples
433+
///
434+
/// ```
435+
/// # use kernel::prelude::*;
436+
/// # use kernel::device::Device;
437+
///
438+
/// fn example(dev: &Device) {
439+
/// dev_err!(dev, "hello {}\n", "there");
440+
/// }
441+
/// ```
442+
#[macro_export]
443+
macro_rules! dev_err {
444+
($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); }
445+
}
446+
447+
/// Prints a warning-level message (level 4) prefixed with device information.
448+
///
449+
/// This level should be used in warning conditions.
450+
///
451+
/// Equivalent to the kernel's `dev_warn` macro.
452+
///
453+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
454+
/// [`core::fmt`] and [`alloc::format!`].
455+
///
456+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
457+
///
458+
/// # Examples
459+
///
460+
/// ```
461+
/// # use kernel::prelude::*;
462+
/// # use kernel::device::Device;
463+
///
464+
/// fn example(dev: &Device) {
465+
/// dev_warn!(dev, "hello {}\n", "there");
466+
/// }
467+
/// ```
468+
#[macro_export]
469+
macro_rules! dev_warn {
470+
($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); }
471+
}
472+
473+
/// Prints a notice-level message (level 5) prefixed with device information.
474+
///
475+
/// This level should be used in normal but significant conditions.
476+
///
477+
/// Equivalent to the kernel's `dev_notice` macro.
478+
///
479+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
480+
/// [`core::fmt`] and [`alloc::format!`].
481+
///
482+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
483+
///
484+
/// # Examples
485+
///
486+
/// ```
487+
/// # use kernel::prelude::*;
488+
/// # use kernel::device::Device;
489+
///
490+
/// fn example(dev: &Device) {
491+
/// dev_notice!(dev, "hello {}\n", "there");
492+
/// }
493+
/// ```
494+
#[macro_export]
495+
macro_rules! dev_notice {
496+
($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); }
497+
}
498+
499+
/// Prints an info-level message (level 6) prefixed with device information.
500+
///
501+
/// This level should be used for informational messages.
502+
///
503+
/// Equivalent to the kernel's `dev_info` macro.
504+
///
505+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
506+
/// [`core::fmt`] and [`alloc::format!`].
507+
///
508+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
509+
///
510+
/// # Examples
511+
///
512+
/// ```
513+
/// # use kernel::prelude::*;
514+
/// # use kernel::device::Device;
515+
///
516+
/// fn example(dev: &Device) {
517+
/// dev_info!(dev, "hello {}\n", "there");
518+
/// }
519+
/// ```
520+
#[macro_export]
521+
macro_rules! dev_info {
522+
($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); }
523+
}
524+
525+
/// Prints a debug-level message (level 7) prefixed with device information.
526+
///
527+
/// This level should be used for debug messages.
528+
///
529+
/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
530+
///
531+
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
532+
/// [`core::fmt`] and [`alloc::format!`].
533+
///
534+
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
535+
///
536+
/// # Examples
537+
///
538+
/// ```
539+
/// # use kernel::prelude::*;
540+
/// # use kernel::device::Device;
541+
///
542+
/// fn example(dev: &Device) {
543+
/// dev_dbg!(dev, "hello {}\n", "there");
544+
/// }
545+
/// ```
546+
#[macro_export]
547+
macro_rules! dev_dbg {
548+
($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); }
549+
}

rust/kernel/prelude.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ pub use macros::module;
1919

2020
pub use super::build_assert;
2121

22-
pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
22+
pub use super::{
23+
dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn,
24+
pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn,
25+
};
2326

2427
pub use super::module_misc_device;
2528

0 commit comments

Comments
 (0)