96 lines
2.6 KiB
Rust
96 lines
2.6 KiB
Rust
use bootloader_api::info::FrameBufferInfo;
|
|
use conquer_once::spin::OnceCell;
|
|
use core::fmt::Write;
|
|
use spinning_top::Spinlock;
|
|
|
|
use super::*;
|
|
|
|
/// The global logger instance used for the `log` crate.
|
|
static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
|
|
|
|
/// A logger instance protected by a spinlock.
|
|
struct LockedLogger {
|
|
framebuffer: Option<Spinlock<framebuffer::FrameBufferWriter>>,
|
|
serial: Option<Spinlock<serial::SerialPort>>
|
|
}
|
|
|
|
impl LockedLogger {
|
|
/// Create a new instance that logs to the given framebuffer.
|
|
pub fn new(
|
|
framebuffer: &'static mut [u8],
|
|
info: FrameBufferInfo,
|
|
) -> Self {
|
|
let framebuffer = Some(Spinlock::new(framebuffer::FrameBufferWriter::new(framebuffer, info)));
|
|
let serial = Some(Spinlock::new(unsafe { serial::SerialPort::init() }));
|
|
|
|
LockedLogger {
|
|
framebuffer,
|
|
serial
|
|
}
|
|
}
|
|
|
|
/// Force-unlocks the logger to prevent a deadlock.
|
|
///
|
|
/// ## Safety
|
|
/// This method is not memory safe and should be only used when absolutely necessary.
|
|
pub unsafe fn force_unlock(&self) {
|
|
if let Some(framebuffer) = &self.framebuffer {
|
|
unsafe { framebuffer.force_unlock() };
|
|
}
|
|
|
|
if let Some(serial) = &self.serial {
|
|
unsafe { serial.force_unlock() };
|
|
}
|
|
}
|
|
}
|
|
|
|
impl log::Log for LockedLogger {
|
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
|
true
|
|
}
|
|
|
|
fn log(&self, record: &log::Record) {
|
|
if let Some(framebuffer) = &self.framebuffer {
|
|
let mut framebuffer = framebuffer.lock();
|
|
writeln!(framebuffer, "{:5}: {}", record.level(), record.args()).unwrap();
|
|
}
|
|
|
|
if let Some(serial) = &self.serial {
|
|
let mut serial = serial.lock();
|
|
writeln!(serial, "{:5}: {}", record.level(), record.args()).unwrap();
|
|
}
|
|
}
|
|
|
|
fn flush(&self) {}
|
|
}
|
|
|
|
/// Initialize a text-based logger using the given pixel-based framebuffer as output.
|
|
pub fn init_logger(
|
|
framebuffer: &'static mut [u8],
|
|
info: FrameBufferInfo,
|
|
) {
|
|
let logger = LOGGER.get_or_init(move || {
|
|
LockedLogger::new(
|
|
framebuffer,
|
|
info,
|
|
)
|
|
});
|
|
log::set_logger(logger).expect("logger already set");
|
|
#[cfg(debug_assertions)]
|
|
log::set_max_level(log::LevelFilter::Debug);
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
log::set_max_level(log::LevelFilter::Info);
|
|
|
|
log::debug!("Framebuffer info: {:?}", info);
|
|
}
|
|
|
|
pub fn force_unlock() {
|
|
unsafe {
|
|
LOGGER
|
|
.get()
|
|
.map(|l| l.force_unlock())
|
|
};
|
|
}
|
|
|