Skip to main content

bootloader_x86_64_common/
logger.rs

1use crate::{framebuffer::FrameBufferWriter, serial::SerialPort};
2use bootloader_api::info::FrameBufferInfo;
3use conquer_once::spin::OnceCell;
4use core::fmt::Write;
5use spinning_top::Spinlock;
6
7/// The global logger instance used for the `log` crate.
8pub static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
9
10/// A logger instance protected by a spinlock.
11pub struct LockedLogger {
12    framebuffer: Option<Spinlock<FrameBufferWriter>>,
13    serial: Option<Spinlock<SerialPort>>,
14}
15
16impl LockedLogger {
17    /// Create a new instance that logs to the given framebuffer.
18    pub fn new(
19        framebuffer: &'static mut [u8],
20        info: FrameBufferInfo,
21        frame_buffer_logger_status: bool,
22        serial_logger_status: bool,
23    ) -> Self {
24        let framebuffer = match frame_buffer_logger_status {
25            true => Some(Spinlock::new(FrameBufferWriter::new(framebuffer, info))),
26            false => None,
27        };
28
29        let serial = match serial_logger_status {
30            true => Some(Spinlock::new(unsafe { SerialPort::init() })),
31            false => None,
32        };
33
34        LockedLogger {
35            framebuffer,
36            serial,
37        }
38    }
39
40    /// Force-unlocks the logger to prevent a deadlock.
41    ///
42    /// ## Safety
43    /// This method is not memory safe and should be only used when absolutely necessary.
44    pub unsafe fn force_unlock(&self) {
45        if let Some(framebuffer) = &self.framebuffer {
46            unsafe { framebuffer.force_unlock() };
47        }
48        if let Some(serial) = &self.serial {
49            unsafe { serial.force_unlock() };
50        }
51    }
52}
53
54impl log::Log for LockedLogger {
55    fn enabled(&self, _metadata: &log::Metadata) -> bool {
56        true
57    }
58
59    fn log(&self, record: &log::Record) {
60        if let Some(framebuffer) = &self.framebuffer {
61            let mut framebuffer = framebuffer.lock();
62            writeln!(framebuffer, "{:5}: {}", record.level(), record.args()).unwrap();
63        }
64        if let Some(serial) = &self.serial {
65            let mut serial = serial.lock();
66            writeln!(serial, "{:5}: {}", record.level(), record.args()).unwrap();
67        }
68    }
69
70    fn flush(&self) {}
71}