From 57fabda3981098e7a540c90414efd6e014c4231d Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 17 Apr 2018 15:57:34 +0800 Subject: [PATCH] Copy serial mod from Redox. Now serial interrupt is working. --- src/arch/x86_64/driver/mod.rs | 1 + src/arch/x86_64/driver/serial.rs | 163 +++++++++++++++++++++++-------- src/arch/x86_64/interrupt/irq.rs | 2 + 3 files changed, 125 insertions(+), 41 deletions(-) diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs index 5322417..ea3f653 100644 --- a/src/arch/x86_64/driver/mod.rs +++ b/src/arch/x86_64/driver/mod.rs @@ -28,5 +28,6 @@ pub fn init(mut page_map: F) } else { pic::init(); } + serial::SERIAL.lock().init(); console::init(); } \ No newline at end of file diff --git a/src/arch/x86_64/driver/serial.rs b/src/arch/x86_64/driver/serial.rs index d6da11a..29fe624 100644 --- a/src/arch/x86_64/driver/serial.rs +++ b/src/arch/x86_64/driver/serial.rs @@ -1,49 +1,130 @@ -/* - * Rust BareBones OS - * - By John Hodge (Mutabah/thePowersGang) - * - * arch/x86/debug.rs - * - Debug output channel - * - * Writes debug to the standard PC serial port (0x3F8 .. 0x3FF) - * - * == LICENCE == - * This code has been put into the public domain, there are no restrictions on - * its use, and the author takes no liability. - */ - -use core::fmt; +use core::fmt::{self, Write}; use spin::Mutex; -use x86_64::instructions::port::{inb, outb}; - -pub static SERIAL: Mutex = Mutex::new(Serial{}); - -pub struct Serial; - -impl Serial { - /// Write a single byte to the output channel - pub fn write(&mut self, byte: u8) { - unsafe { - self.wait(); - - // Send the byte out the serial port - outb(0x3F8, byte); - - // Also send to the bochs 0xe9 hack - outb(0xE9, byte); - } - } - /// Wait for the serial port's fifo to not be empty - unsafe fn wait(&self) { - while (inb(0x3F8+5) & 0x20) == 0 {} - } +use syscall::io::{Io, Pio, Mmio, ReadOnly}; + +pub static SERIAL: Mutex = Mutex::new(Serial::new(0x3F8)); + +#[allow(dead_code)] +pub struct SerialPort> { + /// Data register, read to receive, write to send + data: T, + /// Interrupt enable + int_en: T, + /// FIFO control + fifo_ctrl: T, + /// Line control + line_ctrl: T, + /// Modem control + modem_ctrl: T, + /// Line status + line_sts: ReadOnly, + /// Modem status + modem_sts: ReadOnly, +} + +type Serial = SerialPort>; + +impl SerialPort> { + pub const fn new(base: u16) -> SerialPort> { + SerialPort { + data: Pio::new(base), + int_en: Pio::new(base + 1), + fifo_ctrl: Pio::new(base + 2), + line_ctrl: Pio::new(base + 3), + modem_ctrl: Pio::new(base + 4), + line_sts: ReadOnly::new(Pio::new(base + 5)), + modem_sts: ReadOnly::new(Pio::new(base + 6)) + } + } +} + +impl SerialPort> { + pub fn new(_base: usize) -> SerialPort> { + SerialPort { + data: Mmio::new(), + int_en: Mmio::new(), + fifo_ctrl: Mmio::new(), + line_ctrl: Mmio::new(), + modem_ctrl: Mmio::new(), + line_sts: ReadOnly::new(Mmio::new()), + modem_sts: ReadOnly::new(Mmio::new()) + } + } +} + +impl> SerialPort { + pub fn init(&mut self) { + //TODO: Cleanup + self.int_en.write(0x00); + self.line_ctrl.write(0x80); + self.data.write(0x03); + self.int_en.write(0x00); + self.line_ctrl.write(0x03); + self.fifo_ctrl.write(0xC7); + self.modem_ctrl.write(0x0B); + self.int_en.write(0x01); + } + + fn line_sts(&self) -> LineStsFlags { + LineStsFlags::from_bits_truncate(self.line_sts.read()) + } + + pub fn receive(&mut self) { + while self.line_sts().contains(INPUT_FULL) { + let data = self.data.read(); + write!(self, "serial receive {}", data); + // TODO handle received data + } + } + + fn wait(&self) { + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + } + + pub fn send(&mut self, data: u8) { + match data { + 8 | 0x7F => { + self.wait(); + self.data.write(8); + self.wait(); + self.data.write(b' '); + self.wait(); + self.data.write(8); + }, + _ => { + self.wait(); + self.data.write(data); + } + } + } } -impl fmt::Write for Serial { - fn write_str(&mut self, s: &str) -> fmt::Result { +impl> Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { for byte in s.bytes() { - self.write(byte) + self.send(byte); } Ok(()) } +} + +bitflags! { + /// Interrupt enable flags + flags IntEnFlags: u8 { + const RECEIVED = 1, + const SENT = 1 << 1, + const ERRORED = 1 << 2, + const STATUS_CHANGE = 1 << 3, + // 4 to 7 are unused + } +} + +bitflags! { + /// Line status flags + flags LineStsFlags: u8 { + const INPUT_FULL = 1, + // 1 to 4 unknown + const OUTPUT_EMPTY = 1 << 5, + // 6 and 7 unknown + } } \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 90f71ad..f1e8b49 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -37,7 +37,9 @@ pub extern "x86-interrupt" fn keyboard_handler( pub extern "x86-interrupt" fn serial_handler( stack_frame: &mut ExceptionStackFrame) { + use arch::driver::serial::SERIAL; println!("\nInterupt: Serial \n{:#?}", stack_frame); + SERIAL.lock().receive(); ack(IRQ_COM1); }