#![no_std]
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;
use x86_64::instructions::port::Port;
pub mod kprint;
pub use crate::kprint::DebugSerial;
lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
});
}
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::serial::_print(format_args!($($arg)*));
};
}
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(
concat!($fmt, "\n"), $($arg)*));
}
#[macro_export]
macro_rules! serial_log {
($level:expr, $msg:expr) => {
$crate::serial_write_str($level);
$crate::serial_write_str($msg);
$crate::serial_write_str("\r\n");
};
($level:expr, $fmt:expr, $($arg:tt)*) => {{
use core::fmt::Write;
struct SerialLogger;
impl core::fmt::Write for SerialLogger {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
$crate::serial_write_str(s);
Ok(())
}
}
$crate::serial_write_str($level);
let _ = write!(SerialLogger, $fmt, $($arg)*);
$crate::serial_write_str("\r\n");
}};
}
#[macro_export]
macro_rules! serial_log_hex {
($level:expr, $value:expr) => {
$crate::serial_write_str($level);
$crate::serial_write_str("0x");
$crate::serial_write_hex($value);
$crate::serial_write_str("\r\n");
};
}
const SERIAL_PORT: u16 = 0x3F8;
static mut LOGGING_ENABLED: bool = true;
pub fn enable_serial_logging() {
unsafe {
LOGGING_ENABLED = true;
}
}
pub fn disable_serial_logging() {
unsafe {
LOGGING_ENABLED = false;
}
}
pub fn is_serial_logging_enabled() -> bool {
unsafe { LOGGING_ENABLED }
}
pub fn serial_write_byte(byte: u8) {
if !is_serial_logging_enabled() {
return;
}
unsafe {
let mut line_status = Port::<u8>::new(SERIAL_PORT + 5);
while (line_status.read() & 0x20) == 0 {}
let mut data = Port::new(SERIAL_PORT);
data.write(byte);
}
}
pub fn serial_write_str(s: &str) {
if !is_serial_logging_enabled() {
return;
}
for byte in s.bytes() {
serial_write_byte(byte);
}
}
pub fn serial_write_hex(mut value: u64) {
if !is_serial_logging_enabled() {
return;
}
let mut buf = [0u8; 16];
let mut i = buf.len();
if value == 0 {
serial_write_str("0");
return;
}
while value != 0 {
i -= 1;
let digit = (value & 0xF) as u8;
buf[i] = match digit {
0..=9 => b'0' + digit,
10..=15 => b'A' + (digit - 10),
_ => b'?', };
value >>= 4;
}
serial_write_str(core::str::from_utf8(&buf[i..]).unwrap());
}
pub fn info(text: &str) {
serial_log!("[INFO] ", "{}", text);
}
pub fn info_hex(value: u64) {
serial_log_hex!("[INFO] ", value);
}
pub fn error(text: &str) {
serial_log!("[ERROR] ", "{}", text);
}
pub fn warn(text: &str) {
serial_log!("[WARNING] ", "{}", text);
}
#[macro_export]
macro_rules! error {
($fmt:expr, $($arg:tt)*) => {
$crate::serial_log!("[ERROR] ", $fmt, $($arg)*);
};
($msg:expr) => {
$crate::serial_log!("[ERROR] ", $msg);
};
}