#![no_std] use core::{fmt, sync::atomic::{AtomicUsize, Ordering}}; use spin::Mutex; use lazy_static::lazy_static; mod io; use io::*; use x86_64::instructions::interrupts; static PORT: u16 = 0x3f8; static mut BUFFER: [u8; 256] = [0; 256]; static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0); lazy_static!{ static ref READER: Mutex> = Mutex::new(None); static ref WRITER: Mutex> = Mutex::new(None); } struct Reader; struct Writer; impl fmt::Write for Writer { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { self.write_byte(c as u8); } Ok(()) } } impl Writer { unsafe fn write_success(&self) -> bool { inb(PORT + 5) & 0x20 != 0 } pub fn write_byte(&self, data: u8) { unsafe { while !self.write_success() {}; outb(PORT + 0, data); }} } pub fn init() -> Result<(), &'static str> { if let Err(e) = test() { return Err(e); } if READER.lock().is_none() { *READER.lock() = Some(Reader); } if WRITER.lock().is_none() { *WRITER.lock() = Some(Writer); } Ok(()) } pub fn test() -> Result<(), &'static str> { unsafe { outb(PORT + 1, 0x00); // Disable all interrupts outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud outb(PORT + 1, 0x00); // (hi byte) outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) if inb(PORT + 0) != 0xAE { return Err("serial test failed") } outb(PORT + 4, 0x0F); } Ok(()) } impl Reader { pub fn read_str_to_buffer(&mut self) { unsafe { while !self.read_ready() {}; BUFFER_LEN.store(0, Ordering::SeqCst); while BUFFER_LEN.load(Ordering::SeqCst) < 256 { let c = self.read(); BUFFER[BUFFER_LEN.load(Ordering::SeqCst)] = c; if c as char == '\r' { break; } BUFFER_LEN.fetch_add(1, Ordering::SeqCst); } serial_println!("returning") }} unsafe fn read_ready(&self) -> bool { inb(PORT + 5) & 1 != 0 } pub fn read(&self) -> u8 { unsafe { while !self.read_ready() {}; return inb(PORT + 0); }} } pub fn _serial_write(args: fmt::Arguments) { use core::fmt::Write; interrupts::without_interrupts(|| { if let Some(writer) = WRITER.lock().as_mut() { writer.write_fmt(args).unwrap(); } }) } #[macro_export] macro_rules! serial_println { () => ($crate::serial_print!("\n")); ($($arg:tt)*) => ($crate::serial_print!("{}\n", format_args!($($arg)*))); } #[macro_export] macro_rules! serial_print { ($($arg:tt)*) => ($crate::_serial_write(format_args!($($arg)*))); } pub fn serial_read() -> &'static str { serial_println!("getting value!"); interrupts::without_interrupts(|| { if let Some(reader) = READER.lock().as_mut() { serial_println!("stuff happnin."); reader.read_str_to_buffer(); } else { serial_println!("failed to get writer"); } }); serial_println!("eee"); let i = BUFFER_LEN.load(Ordering::SeqCst); return unsafe { if i != 0 { core::str::from_utf8(&BUFFER[..i - 1]).unwrap() } else { serial_println!("empty string"); "" } } }