3966e697da
- reorganised the entire project so that the entire kernel is a single codebase rather than a kernel and a libk.
156 lines
3.7 KiB
Rust
156 lines
3.7 KiB
Rust
use core::{
|
|
fmt,
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
};
|
|
use spin::{Lazy, Mutex};
|
|
|
|
#[macro_export]
|
|
macro_rules! serial_print {
|
|
($($arg:tt)*) => ($crate::_serial_write(format_args!($($arg)*)));
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! serial_println {
|
|
() => ($crate::serial_print!("\n"));
|
|
($($arg:tt)*) => (serial_print!("{}\n", format_args!($($arg)*)));
|
|
}
|
|
|
|
use crate::arch::x86_64::drivers::port::{inb, outb};
|
|
|
|
use x86_64::instructions::interrupts;
|
|
|
|
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();
|
|
}
|
|
})
|
|
}
|
|
|
|
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);
|
|
|
|
unsafe {
|
|
if i != 0 {
|
|
core::str::from_utf8(&BUFFER[..i - 1]).unwrap()
|
|
} else {
|
|
serial_println!("empty string");
|
|
""
|
|
}
|
|
}
|
|
}
|
|
|
|
static PORT: u16 = 0x3f8;
|
|
static mut BUFFER: [u8; 256] = [0; 256];
|
|
static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
static READER: Lazy<Mutex<Option<Reader>>> = Lazy::new(|| Mutex::new(None));
|
|
static WRITER: Lazy<Mutex<Option<Writer>>> = Lazy::new(|| 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, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn init() -> Result<(), &'static str> {
|
|
test()?;
|
|
|
|
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> {
|
|
outb(PORT + 1, 0x00); // Disable all interrupts
|
|
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
|
outb(PORT, 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, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
|
|
|
|
if inb(PORT) != 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() {}
|
|
inb(PORT)
|
|
}
|
|
}
|
|
}
|