//! This optional feature adds support for the `log` crate, providing
//! a custom logger implementation which writes to a UEFI text output protocol.
//!
//! The main export of this module is the `Logger` structure,
//! which implements the `log` crate's trait `Log`.
//!
//! # Implementation details
//!
//! The implementation is not the most efficient, since there is no buffering done,
//! and the messages have to be converted from UTF-8 to UEFI's UCS-2.
//!
//! The last part also means that some Unicode characters might not be
//! supported by the UEFI console. Don't expect emoji output support.
use crate::proto::console::text::Output;
use crate::system;
use core::fmt::{self, Write};
use core::ptr;
use core::sync::atomic::{AtomicPtr, Ordering};
/// Global logger object
static LOGGER: Logger = Logger::new();
/// Set up logging
///
/// This is unsafe because you must arrange for the logger to be reset with
/// disable() on exit from UEFI boot services.
pub unsafe fn init() {
// Connect the logger to stdout.
system::with_stdout(|stdout| {
LOGGER.set_output(stdout);
});
// Set the logger.
log::set_logger(&LOGGER).unwrap(); // Can only fail if already initialized.
// Set logger max level to level specified by log features
log::set_max_level(log::STATIC_MAX_LEVEL);
}
pub fn disable() {
LOGGER.disable();
}
/// Writer to the QEMU debugcon device and the debug-console of
/// cloud-hypervisor.
///
/// More info:
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "log-debugcon"
))]
#[derive(Copy, Clone, Debug)]
struct DebugconWriter;
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "log-debugcon"
))]
impl DebugconWriter {
const IO_PORT: u16 = 0xe9;
}
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "log-debugcon"
))]
impl core::fmt::Write for DebugconWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
for &byte in s.as_bytes() {
unsafe {
core::arch::asm!("outb %al, %dx", in("al") byte, in("dx") Self::IO_PORT, options(att_syntax))
};
}
Ok(())
}
}
/// Logging implementation which writes to a UEFI output stream.
///
/// If this logger is used as a global logger, you must disable it using the
/// `disable` method before exiting UEFI boot services in order to prevent
/// undefined behaviour from inadvertent logging.
#[derive(Debug)]
pub struct Logger {
writer: AtomicPtr