use core::arch::asm; use core::fmt::Write; use crate::mem::allocator::Locked; pub struct SerialPort(u16); impl SerialPort { pub const COM1: u16 = 0x3F8; pub unsafe fn init() -> Self { let port = Self::COM1; unsafe { outb(port + 1, 0x00); outb(port + 3, 0x80); outb(port + 0, 0x03); outb(port + 1, 0x00); outb(port + 3, 0x03); outb(port + 2, 0xC7); outb(port + 4, 0x0B); } SerialPort(port) } fn is_transmit_empty(&self) -> bool { unsafe { (inb(self.0 + 5) & 0x20) != 0 } } pub fn send(&self, data: u8) { while !self.is_transmit_empty() {} unsafe { outb(self.0, data); } } } impl core::fmt::Write for SerialPort { fn write_str(&mut self, s: &str) -> core::fmt::Result { for byte in s.bytes() { self.send(byte); } Ok(()) } } static SERIAL_PORT: Locked> = Locked::new(None); pub fn init_global() { let mut guard = SERIAL_PORT.lock(); *guard = Some(unsafe { SerialPort::init() }); } pub fn write_global(args: core::fmt::Arguments) { let mut guard = SERIAL_PORT.lock(); if let Some(ref mut sp) = *guard { let _ = sp.write_fmt(args); } } unsafe fn outb(port: u16, val: u8) { unsafe { asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags)); } } unsafe fn inb(port: u16) -> u8 { let res: u8; unsafe { asm!("in al, dx", out("al") res, in("dx") port, options(nomem, nostack, preserves_flags)); } res }