diff --git a/src/kernel/arch/x86_64/serial.rs b/src/kernel/arch/x86_64/serial.rs index b4ea02e..c968786 100644 --- a/src/kernel/arch/x86_64/serial.rs +++ b/src/kernel/arch/x86_64/serial.rs @@ -9,6 +9,8 @@ use num_derive::FromPrimitive; use num_traits::FromPrimitive; use x86_64::instructions::port::Port; +use crate::arch::asm::nop; + /// Represents an x86 port-mapped serial port. pub struct SerialPort { base_port: Port, @@ -21,6 +23,7 @@ pub struct SerialPort { scratch: Port, fifo_register: u8, pub crlf: Crlf, + pub wait_tx_clear: bool, } #[derive(PartialEq, Eq)] @@ -123,7 +126,6 @@ pub enum ModemStatus { DataCarrierDetect = 0b10000000, } -// TODO: Ensure we don't clobber the tx buffer and prevent some data from getting printed impl SerialPort { pub fn log_write(&mut self, msg: &str) { if self.crlf == Crlf::Crlf { @@ -140,10 +142,18 @@ impl SerialPort { } } + /// Get whether the transmit buffer is empty. pub fn is_transmit_empty(&mut self) -> bool { - self.get_interrupt_state() != InterruptState::TransmitterEmpty + self.get_line_status().contains(LineStatus::TransmitterEmpty) } + fn block_until_transmit_empty(&mut self) { + while !self.is_transmit_empty() { + nop(); + } + } + + /// Write a message with a newline appended to the serial port. pub fn log_writeln(&mut self, msg: &str) { self.log_write(msg); self.log_write("\n"); @@ -162,6 +172,7 @@ impl SerialPort { scratch: Port::new(port_addr + 7), fifo_register: 0, crlf: Crlf::Crlf, + wait_tx_clear: true, }; // ensure this is false port.set_dlab(false); @@ -190,6 +201,10 @@ impl SerialPort { } /// Write a single character to the TX buffer. pub fn write_char(&mut self, c: char) { + // Wait for the TX Buffer to be empty + if self.wait_tx_clear { + self.block_until_transmit_empty(); + } unsafe { self.base_port.write(c as u8) }; }