pub mod uart_16550 { #![cfg(target_arch = "x86_64")] use crate::x86_64::PortU16; use core::mem::MaybeUninit; pub struct Uart16550 { pub base_port: PortU16, pub baud_rate: BaudRate, pub parity: Parity, pub stop_bits: StopBits, pub data_bits: DataBits, pub fifo_trigger_level: Option, pub interrupt_enable: InterruptEnable, } impl Uart16550 { /// Transmitter/Receiver Holding Register offset pub const DATA: u16 = 0x0; /// Interrupt Enable Register offset pub const IER: u16 = 0x1; /// Interrupt Status Register offset pub const ISR: u16 = 0x2; /// FIFO Control Register offset pub const FCR: u16 = 0x2; /// Line Control Register offset pub const LCR: u16 = 0x3; /// Modem Control Register offset pub const MCR: u16 = 0x4; /// Line Status Register offset pub const LSR: u16 = 0x5; /// Modem Status Register offset pub const MSR: u16 = 0x6; /// Scratch Pad Register offset pub const SPR: u16 = 0x7; /// Divisor Latch Low offset pub const DLL: u16 = 0x0; /// Divisor Latch High offset pub const DLM: u16 = 0x1; /// # Safety /// This function creates a new instance of Uart16550 with the given base port. pub unsafe fn with_port(base_port: u16) -> Self { Self { base_port: PortU16(base_port), baud_rate: BaudRate::default(), parity: Parity::default(), stop_bits: StopBits::default(), data_bits: DataBits::default(), fifo_trigger_level: Some(FifoTriggerLevel::default()), interrupt_enable: InterruptEnable::default(), } } pub fn init(&mut self) { unsafe { self.base_port.offset(Self::IER).write(0); self.base_port.offset(Self::LCR).write(0); } self.set_baud_rate(self.baud_rate); let lcr = LineControl::new(false, false, self.parity, self.stop_bits, self.data_bits); unsafe { self.write_lcr(lcr); let mut fcr = FifoControl::empty(); if let Some(level) = self.fifo_trigger_level { fcr.set_fifo_enable(true); fcr.set_fifo_trigger_level(level); } fcr.set_clear_receive_fifo(); fcr.set_clear_transmit_fifo(); self.write_fcr(fcr); let mut mcr = ModemControl::empty(); mcr.set_data_terminal_ready(true); mcr.set_request_to_send(true); mcr.set_auxiliary_output_2(true); self.write_mcr(mcr); self.write_ier(self.interrupt_enable); loop { let lsr = self.read_lsr(); if lsr.transmitter_holding_register_empty() { break; } core::hint::spin_loop(); } } } pub fn ready_to_receive(&self) -> bool { let lsr = self.read_lsr(); lsr.data_ready() } pub fn ready_to_send(&self) -> bool { let lsr = self.read_lsr(); let msr = self.read_msr(); let mcr = self.read_mcr(); if !lsr.transmitter_holding_register_empty() { return false; } if !mcr.loopback_mode() && !msr.clear_to_send() { return false; } true } pub fn try_receive_byte(&self) -> Option { if self.ready_to_receive() { let data_port = self.base_port.offset(Self::DATA); let value = unsafe { data_port.read() } as u8; Some(value) } else { None } } pub fn try_send_bytes(&self, bytes: &[u8]) -> Option { if bytes.is_empty() { return Some(0); } if !self.ready_to_send() { return None; } let bytes = match self.fifo_trigger_level { None => &bytes[..1], Some(level) => { let end = core::cmp::min(bytes.len(), level.count()); &bytes[..end] } }; for &b in bytes { unsafe { self.base_port.offset(Self::DATA).write(b as u16); } } Some(bytes.len()) } pub fn try_send_byte(&self, byte: u8) -> Option<()> { if self.ready_to_send() { let data_port = self.base_port.offset(Self::DATA); unsafe { data_port.write(byte as u16) }; Some(()) } else { None } } pub fn try_receive_bytes<'a>( &self, buffer: &'a mut [MaybeUninit], ) -> (&'a mut [u8], &'a mut [MaybeUninit]) { let len = buffer .iter_mut() .map_while(|b: &mut MaybeUninit| { self.try_receive_byte().map(|val| b.write(val)) }) .count(); // SAFETY: We have just initialized the first `len` elements of the // buffer, so it is safe to transmute them to `&mut [u8]`. unsafe { let (init, uninit) = buffer.split_at_mut(len); let init = core::mem::transmute::<&mut [MaybeUninit], &mut [u8]>(init); (init, uninit) } } pub fn receive_bytes_exact<'a>(&self, buffer: &'a mut [MaybeUninit]) -> &'a mut [u8] { let (ptr, len) = (buffer.as_mut_ptr(), buffer.len()); let mut rest = buffer; loop { rest = self.try_receive_bytes(rest).1; if rest.is_empty() { break; } } unsafe { // SAFETY: We have just initialized the entire buffer, so it is safe to transmute it to `&mut [u8]`. core::slice::from_raw_parts_mut(ptr as *mut u8, len) } } pub fn send_bytes_exact(&self, bytes: &[u8]) { let mut rest = bytes; loop { let sent = self.try_send_bytes(rest).unwrap_or(0); rest = &rest[sent..]; if rest.is_empty() { break; } } } pub fn read_lcr(&self) -> LineControl { let lcr_port = self.base_port.offset(3); let value = unsafe { lcr_port.read() } as u8; LineControl(value) } /// # Safety /// This function writes to the Line Control Register (LCR) of the UART. pub unsafe fn write_lcr(&self, lcr: LineControl) { let lcr_port = self.base_port.offset(Self::LCR); unsafe { lcr_port.write(lcr.0 as u16) }; } pub fn read_msr(&self) -> ModemStatus { let msr_port = self.base_port.offset(Self::MSR); let value = unsafe { msr_port.read() } as u8; ModemStatus(value) } pub fn read_lsr(&self) -> LineStatus { let lsr_port = self.base_port.offset(Self::LSR); let value = unsafe { lsr_port.read() } as u8; LineStatus(value) } pub fn read_ier(&self) -> InterruptEnable { let ier_port = self.base_port.offset(Self::IER); let value = unsafe { ier_port.read() } as u8; InterruptEnable(value) } /// # Safety /// This function writes to the Interrupt Enable Register (IER) of the UART. pub unsafe fn write_ier(&self, ier: InterruptEnable) { let ier_port = self.base_port.offset(Self::IER); unsafe { ier_port.write(ier.0 as u16) }; } pub fn read_isr(&self) -> InterruptStatus { let isr_port = self.base_port.offset(Self::ISR); let value = unsafe { isr_port.read() } as u8; InterruptStatus(value) } pub fn read_fcr(&self) -> FifoControl { let fcr_port = self.base_port.offset(Self::FCR); let value = unsafe { fcr_port.read() } as u8; FifoControl(value) } pub fn read_mcr(&self) -> ModemControl { let mcr_port = self.base_port.offset(Self::MCR); let value = unsafe { mcr_port.read() } as u8; ModemControl(value) } /// # Safety /// This function writes to the Modem Control Register (MCR) of the UART. pub unsafe fn write_mcr(&self, mcr: ModemControl) { let mcr_port = self.base_port.offset(Self::MCR); unsafe { mcr_port.write(mcr.0 as u16) }; } /// # Safety /// This function writes to the FIFO Control Register (FCR) of the UART. pub unsafe fn write_fcr(&self, fcr: FifoControl) { let fcr_port = self.base_port.offset(Self::FCR); unsafe { fcr_port.write(fcr.0 as u16) }; } pub fn set_baud_rate(&self, baud_rate: BaudRate) { let divisor = baud_rate.divisor(); let mut lcr = self.read_lcr(); lcr.set_dlab(true); let [low_byte, high_byte] = divisor.to_le_bytes(); unsafe { self.write_lcr(lcr); self.base_port.offset(Self::DLL).write(low_byte as u16); self.base_port.offset(Self::DLM).write(high_byte as u16); lcr.set_dlab(false); self.write_lcr(lcr); } } } const BASE_RATE: u32 = 115200; #[derive(Debug, Clone, Copy, Default)] pub enum BaudRate { #[default] Baud115200, Baud57600, Baud38400, Baud19200, Baud9600, } impl BaudRate { pub fn divisor(&self) -> u16 { let rate = match self { BaudRate::Baud115200 => 115200, BaudRate::Baud57600 => 57600, BaudRate::Baud38400 => 38400, BaudRate::Baud19200 => 19200, BaudRate::Baud9600 => 9600, }; assert!(BASE_RATE.is_multiple_of(rate), "Invalid baud rate"); (BASE_RATE / rate) as u16 } } #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct LineControl(pub u8); #[derive(Debug, Clone, Copy, Default)] #[repr(u8)] pub enum DataBits { Five = 0b00, Six = 0b01, Seven = 0b10, #[default] Eight = 0b11, } #[derive(Debug, Clone, Copy, Default)] #[repr(u8)] pub enum StopBits { #[default] One = 0b0, Two = 0b1, } #[derive(Debug, Clone, Copy, Default)] #[repr(u8)] pub enum Parity { #[default] None = 0b00, Odd = 0b01, Even = 0b11, Mark = 0b101, Space = 0b111, } impl LineControl { pub const fn empty() -> Self { Self(0) } pub fn dlab(&self) -> bool { (self.0 & (1 << 7)) != 0 } pub fn set_dlab(&mut self, dlab: bool) { if dlab { self.0 |= 1 << 7; } else { self.0 &= !(1 << 7); } } pub fn set_break_signal(&mut self, break_signal: bool) { if break_signal { self.0 |= 1 << 6; } else { self.0 &= !(1 << 6); } } pub fn break_signal(&self) -> bool { (self.0 & (1 << 6)) != 0 } pub fn set_parity(&mut self, parity: Parity) { self.0 &= !(0b111 << 3); self.0 |= (parity as u8) << 3; } pub fn parity(&self) -> Parity { match (self.0 >> 3) & 0b111 { 0b000 => Parity::None, 0b001 => Parity::Odd, 0b011 => Parity::Even, 0b101 => Parity::Mark, 0b111 => Parity::Space, _ => unreachable!(), } } pub fn set_stop_bits(&mut self, stop_bits: StopBits) { self.0 &= !(1 << 2); self.0 |= (stop_bits as u8) << 2; } pub fn stop_bits(&self) -> StopBits { match (self.0 >> 2) & 0b1 { 0b0 => StopBits::One, 0b1 => StopBits::Two, _ => unreachable!(), } } pub fn set_data_bits(&mut self, data_bits: DataBits) { self.0 &= !(0b11); self.0 |= data_bits as u8; } pub fn data_bits(&self) -> DataBits { match self.0 & 0b11 { 0b00 => DataBits::Five, 0b01 => DataBits::Six, 0b10 => DataBits::Seven, 0b11 => DataBits::Eight, _ => unreachable!(), } } pub const fn new( dlab: bool, break_signal: bool, parity: Parity, stop_bits: StopBits, data_bits: DataBits, ) -> Self { let mut value = 0u8; if dlab { value |= 1 << 7; } if break_signal { value |= 1 << 6; } value |= (parity as u8) << 3; value |= (stop_bits as u8) << 2; value |= data_bits as u8; Self(value) } } #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct InterruptEnable(pub u8); impl Default for InterruptEnable { fn default() -> Self { let mut empty = Self(0); empty.set_received_data_available(true); empty } } impl InterruptEnable { pub const fn empty() -> Self { Self(0) } pub fn set_received_data_available(&mut self, enable: bool) { if enable { self.0 |= 1 << 0; } else { self.0 &= !(1 << 0); } } pub fn received_data_available(&self) -> bool { (self.0 & (1 << 0)) != 0 } pub fn set_transmitter_holding_register_empty(&mut self, enable: bool) { if enable { self.0 |= 1 << 1; } else { self.0 &= !(1 << 1); } } pub fn transmitter_holding_register_empty(&self) -> bool { (self.0 & (1 << 1)) != 0 } pub fn set_receiver_line_status(&mut self, enable: bool) { if enable { self.0 |= 1 << 2; } else { self.0 &= !(1 << 2); } } pub fn receiver_line_status(&self) -> bool { (self.0 & (1 << 2)) != 0 } pub fn set_modem_status(&mut self, enable: bool) { if enable { self.0 |= 1 << 3; } else { self.0 &= !(1 << 3); } } pub fn modem_status(&self) -> bool { (self.0 & (1 << 3)) != 0 } } pub struct FifoControl(pub u8); impl FifoControl { pub const fn empty() -> Self { Self(0) } pub fn set_fifo_enable(&mut self, enable: bool) { if enable { self.0 |= 1 << 0; } else { self.0 &= !(1 << 0); } } pub fn fifo_enable(&self) -> bool { (self.0 & (1 << 0)) != 0 } pub fn set_fifo_trigger_level(&mut self, level: FifoTriggerLevel) { self.0 &= !(0b11 << 6); self.0 |= (level as u8) << 6; } pub fn fifo_trigger_level(&self) -> FifoTriggerLevel { match (self.0 >> 6) & 0b11 { 0b00 => FifoTriggerLevel::Level1Byte, 0b01 => FifoTriggerLevel::Level4Bytes, 0b10 => FifoTriggerLevel::Level8Bytes, 0b11 => FifoTriggerLevel::Level14Bytes, _ => unreachable!(), } } pub fn set_clear_receive_fifo(&mut self) { self.0 |= 1 << 1; } pub fn set_clear_transmit_fifo(&mut self) { self.0 |= 1 << 2; } pub fn set_dma_mode(&mut self, enable: bool) { if enable { self.0 |= 1 << 3; } else { self.0 &= !(1 << 3); } } } #[repr(u8)] pub enum InterruptState { ModemStatus = 0, TransmitterHoldingRegisterEmpty = 1, ReceivedDataAvailable = 2, ReceiverLineStatus = 3, } #[repr(u8)] pub enum FIFOBufferState { Disabled = 0, Unusable = 1, Enabled = 2, } pub struct InterruptStatus(pub u8); impl InterruptStatus { pub fn interrupt_pending(&self) -> bool { (self.0 & (1 << 0)) == 0 } pub fn timeout_interrupt_pending(&self) -> bool { (self.0 & (1 << 4)) != 0 } pub fn interrupt_state(&self) -> InterruptState { match (self.0 >> 1) & 0b111 { 0b000 => InterruptState::ModemStatus, 0b001 => InterruptState::TransmitterHoldingRegisterEmpty, 0b010 => InterruptState::ReceivedDataAvailable, 0b011 => InterruptState::ReceiverLineStatus, _ => unreachable!(), } } pub fn fifo_buffer_state(&self) -> FIFOBufferState { match (self.0 >> 6) & 0b11 { 0b00 => FIFOBufferState::Disabled, 0b01 => FIFOBufferState::Unusable, 0b10 => FIFOBufferState::Enabled, _ => unreachable!(), } } } pub struct ModemControl(pub u8); impl ModemControl { pub const fn empty() -> Self { Self(0) } pub fn set_data_terminal_ready(&mut self, enable: bool) { if enable { self.0 |= 1 << 0; } else { self.0 &= !(1 << 0); } } pub fn set_request_to_send(&mut self, enable: bool) { if enable { self.0 |= 1 << 1; } else { self.0 &= !(1 << 1); } } pub fn set_auxiliary_output_1(&mut self, enable: bool) { if enable { self.0 |= 1 << 2; } else { self.0 &= !(1 << 2); } } pub fn set_auxiliary_output_2(&mut self, enable: bool) { if enable { self.0 |= 1 << 3; } else { self.0 &= !(1 << 3); } } pub fn set_loopback_mode(&mut self, enable: bool) { if enable { self.0 |= 1 << 4; } else { self.0 &= !(1 << 4); } } pub fn loopback_mode(&self) -> bool { (self.0 & (1 << 4)) != 0 } } pub struct LineStatus(pub u8); impl LineStatus { pub fn data_ready(&self) -> bool { (self.0 & (1 << 0)) != 0 } pub fn overrun_error(&self) -> bool { (self.0 & (1 << 1)) != 0 } pub fn parity_error(&self) -> bool { (self.0 & (1 << 2)) != 0 } pub fn framing_error(&self) -> bool { (self.0 & (1 << 3)) != 0 } pub fn break_interrupt(&self) -> bool { (self.0 & (1 << 4)) != 0 } pub fn transmitter_holding_register_empty(&self) -> bool { (self.0 & (1 << 5)) != 0 } pub fn transmitter_empty(&self) -> bool { (self.0 & (1 << 6)) != 0 } pub fn impending_error(&self) -> bool { (self.0 & (1 << 7)) != 0 } } pub struct ModemStatus(pub u8); impl ModemStatus { pub fn delta_clear_to_send(&self) -> bool { (self.0 & (1 << 0)) != 0 } pub fn delta_data_set_ready(&self) -> bool { (self.0 & (1 << 1)) != 0 } pub fn trailing_edge_ring_indicator(&self) -> bool { (self.0 & (1 << 2)) != 0 } pub fn delta_data_carrier_detect(&self) -> bool { (self.0 & (1 << 3)) != 0 } pub fn clear_to_send(&self) -> bool { (self.0 & (1 << 4)) != 0 } pub fn data_set_ready(&self) -> bool { (self.0 & (1 << 5)) != 0 } pub fn ring_indicator(&self) -> bool { (self.0 & (1 << 6)) != 0 } pub fn data_carrier_detect(&self) -> bool { (self.0 & (1 << 7)) != 0 } } #[derive(Debug, Clone, Copy, Default)] #[repr(u8)] pub enum FifoTriggerLevel { Level1Byte = 0b00, Level4Bytes = 0b01, Level8Bytes = 0b10, #[default] Level14Bytes = 0b11, } impl FifoTriggerLevel { pub fn count(&self) -> usize { match self { FifoTriggerLevel::Level1Byte => 1, FifoTriggerLevel::Level4Bytes => 4, FifoTriggerLevel::Level8Bytes => 8, FifoTriggerLevel::Level14Bytes => 14, } } } pub struct Uart16550Writer { uart: Uart16550, } impl Uart16550Writer { pub fn from_port(base_port: u16) -> Self { let mut uart = unsafe { Uart16550::with_port(base_port) }; uart.init(); Self { uart } } } impl core::fmt::Write for Uart16550Writer { fn write_str(&mut self, s: &str) -> core::fmt::Result { let bytes = s.as_bytes(); const SPECIAL_BYTES: &[u8] = &[b'\n', 8, 0x7f]; bytes .split_inclusive(|b| SPECIAL_BYTES.contains(b)) .for_each(|chunk| { if let Some((special, rest)) = chunk.split_last() { self.uart.send_bytes_exact(rest); match special { b'\n' => { self.uart.send_bytes_exact(b"\r\n"); } 8 | 0x7f => { // Backspace or Delete: send backspace, space, // backspace to erase the character on the // terminal self.uart.send_bytes_exact(&[8, b' ', 8]); } _ => { self.uart.send_bytes_exact(&[*special]); } } } }); Ok(()) } } pub static SERIAL1: crate::sync::LazyLock> = crate::sync::LazyLock::new(|| { crate::sync::SpinMutex::new(Uart16550Writer::from_port(0x3f8)) }); } #[doc(hidden)] pub fn _print(args: core::fmt::Arguments, nl: bool) { #[cfg(target_arch = "x86_64")] { use core::fmt::Write; struct Writer<'a>(&'a crate::sync::SpinMutex); impl core::fmt::Write for Writer<'_> { fn write_str(&mut self, s: &str) -> core::fmt::Result { let mut writer = self.0.lock(); writer.write_str(s) } } let mut writer = Writer(&uart_16550::SERIAL1); writer.write_fmt(args).unwrap(); if nl { writer.write_str("\n").unwrap(); } } } #[macro_export] macro_rules! serial_print { ($($arg:tt)*) => { $crate::serial::_print(format_args!($($arg)*), false); }; } #[macro_export] macro_rules! serial_println { () => { $crate::serial_print!("\n"); }; ($($arg:tt)*) => { $crate::serial::_print(format_args!($($arg)*), true); }; }