kernel/io/
mod.rs

1use core::{fmt, sync::atomic::AtomicBool};
2
3pub mod console;
4mod uart;
5
6static PRINT_ERR: AtomicBool = AtomicBool::new(false);
7
8macro_rules! impl_copy_clone_deref_wrapper {
9    ($new_type:tt <$generic:tt>) => {
10        impl<$generic> ::core::clone::Clone for $new_type<$generic>
11        where
12            $generic: ::core::clone::Clone,
13        {
14            fn clone(&self) -> Self {
15                $new_type(self.0.clone())
16            }
17        }
18
19        impl<$generic> ::core::marker::Copy for $new_type<$generic> where
20            $generic: ::core::marker::Copy
21        {
22        }
23
24        impl<$generic> ::core::ops::Deref for $new_type<$generic> {
25            type Target = $generic;
26
27            fn deref(&self) -> &Self::Target {
28                &self.0
29            }
30        }
31
32        impl<$generic> ::core::ops::DerefMut for $new_type<$generic> {
33            fn deref_mut(&mut self) -> &mut Self::Target {
34                &mut self.0
35            }
36        }
37    };
38}
39
40// This is a wrapper around a type that implements Debug, but we don't want to print it
41// its kinda like using some libraries that allow you to disable debug for some fields
42#[repr(transparent)]
43pub struct NoDebug<T>(pub T);
44
45impl<T> fmt::Debug for NoDebug<T> {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        write!(f, "[no_debug]")
48    }
49}
50
51impl_copy_clone_deref_wrapper!(NoDebug<T>);
52
53// This is a wrapper around a arrays/vectors to make them display proper hex in 1 line
54#[repr(transparent)]
55pub struct HexArray<T>(pub T);
56
57// a private trait to make the compiler happy about usage of `U` constraint
58trait ArrayTrait {
59    type Item;
60    fn data(&self) -> &[Self::Item];
61}
62
63impl<T> ArrayTrait for T
64where
65    T: AsRef<[u8]>,
66{
67    type Item = u8;
68    fn data(&self) -> &[Self::Item] {
69        self.as_ref()
70    }
71}
72
73impl<T, U> fmt::Debug for HexArray<T>
74where
75    T: ArrayTrait<Item = U>,
76    U: fmt::UpperHex,
77{
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        // write!(f, "[no_debug]")
80        write!(f, "[")?;
81        for (index, data) in self.0.data().iter().enumerate() {
82            if index > 0 {
83                write!(f, ", ")?;
84            }
85            // for now we use 04 width, which won't work as expected for u16/u32/u64
86            // but we don't use them for now
87            write!(f, "{data:#04X}")?;
88        }
89        write!(f, "]")
90    }
91}
92
93impl_copy_clone_deref_wrapper!(HexArray<T>);
94
95// This is a wrapper around a byte array that allows us to print it as a string
96#[repr(transparent)]
97pub struct ByteStr<T>(pub T);
98
99impl<T> fmt::Debug for ByteStr<T>
100where
101    T: AsRef<[u8]>,
102{
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(f, "b\"")?;
105        // display each char if printable, otherwise replace with \xXX
106        for &c in self.0.as_ref().iter() {
107            if c.is_ascii_graphic() || c == b' ' {
108                write!(f, "{}", c as char)?;
109            } else {
110                write!(f, "\\x{c:02X}")?;
111            }
112        }
113        write!(f, "\"")
114    }
115}
116
117impl_copy_clone_deref_wrapper!(ByteStr<T>);
118
119#[allow(dead_code)]
120pub fn hexdump(buf: &[u8]) {
121    // lock first so that none else can access the console
122    // its ReMutex, so we can acquire the lock
123    console::run_with_console(|inner| {
124        // print hex dump
125        for i in 0..buf.len() / 16 {
126            write!(inner, "{:08X}:  ", i * 16)?;
127            for j in 0..16 {
128                write!(inner, "{:02X} ", buf[i * 16 + j])?;
129            }
130            // print ascii
131            write!(inner, "  ")?;
132            for j in 0..16 {
133                let c = buf[i * 16 + j];
134                if (32..127).contains(&c) {
135                    write!(inner, "{}", c as char)?;
136                } else {
137                    write!(inner, ".")?;
138                }
139            }
140            writeln!(inner)?;
141        }
142        // print remaining if any
143        let remaining = buf.len() % 16;
144        if remaining != 0 {
145            let remaining_start = (buf.len() / 16) * 16;
146
147            write!(inner, "{remaining_start:08X}:  ")?;
148            for c in buf[remaining_start..].iter() {
149                write!(inner, "{c:02X} ")?;
150            }
151            for _ in 0..(16 - remaining) {
152                write!(inner, "   ")?;
153            }
154            // print ascii
155            write!(inner, "  ")?;
156            for &c in buf[remaining_start..].iter() {
157                if (32..127).contains(&c) {
158                    write!(inner, "{}", c as char)?;
159                } else {
160                    write!(inner, ".")?;
161                }
162            }
163            writeln!(inner)?;
164        }
165        Ok::<(), fmt::Error>(())
166    })
167    .unwrap();
168}
169
170pub fn _print(args: ::core::fmt::Arguments) {
171    console::run_with_console(|inner| inner.write_fmt(args)).unwrap();
172}
173
174// Enable `eprint!` and `eprintln!` macros
175// sort of toggleable logging
176#[allow(dead_code)]
177pub fn set_err_enable(enable: bool) {
178    PRINT_ERR.store(enable, core::sync::atomic::Ordering::Release);
179}
180
181pub fn _eprint(args: ::core::fmt::Arguments) {
182    if PRINT_ERR.load(core::sync::atomic::Ordering::Acquire) {
183        _print(args);
184    }
185}