From 0e1d664bf0ac733c043b31cb54be2833c65c1474 Mon Sep 17 00:00:00 2001 From: Tommy Hudson Date: Sun, 30 Jul 2017 20:54:36 +0100 Subject: [PATCH] Rearrange serial I/O code and make 16550 driver generic over T: Io --- src/arch/mod.rs | 6 +- src/arch/x86_64/device/serial.rs | 112 +--------------------------- src/arch/x86_64/macros.rs | 17 +++++ src/devices/mod.rs | 1 + src/devices/uart_16550.rs | 122 +++++++++++++++++++++++++++++++ src/lib.rs | 13 ++-- src/macros.rs | 16 ---- 7 files changed, 155 insertions(+), 132 deletions(-) create mode 100644 src/devices/mod.rs create mode 100644 src/devices/uart_16550.rs delete mode 100644 src/macros.rs diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 0bffdbe..1abbd03 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -1 +1,5 @@ -pub mod x86_64; \ No newline at end of file +#[cfg(target_arch = "x86_64")] +#[macro_use] +pub mod x86_64; +#[cfg(target_arch = "x86_64")] +pub use self::x86_64::*; \ No newline at end of file diff --git a/src/arch/x86_64/device/serial.rs b/src/arch/x86_64/device/serial.rs index b29c8b0..05905a7 100644 --- a/src/arch/x86_64/device/serial.rs +++ b/src/arch/x86_64/device/serial.rs @@ -1,115 +1,11 @@ -use core::fmt::{self, Write}; +use devices::uart_16550::SerialPort; +use syscall::io::Pio; use spin::Mutex; -use scheme::debug::debug_input; -use syscall::io::{Io, Pio, ReadOnly}; - -pub static COM1: Mutex = Mutex::new(SerialPort::new(0x3F8)); -pub static COM2: Mutex = Mutex::new(SerialPort::new(0x2F8)); +pub static COM1: Mutex>> = Mutex::new(SerialPort::>::new(0x3F8)); +pub static COM2: Mutex>> = Mutex::new(SerialPort::>::new(0x2F8)); pub unsafe fn init() { COM1.lock().init(); COM2.lock().init(); } - -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 - } -} - -#[allow(dead_code)] -pub struct SerialPort { - /// Data register, read to receive, write to send - data: Pio, - /// Interrupt enable - int_en: Pio, - /// FIFO control - fifo_ctrl: Pio, - /// Line control - line_ctrl: Pio, - /// Modem control - modem_ctrl: Pio, - /// Line status - line_sts: ReadOnly>, - /// Modem status - modem_sts: ReadOnly>, -} - -impl SerialPort { - 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)) - } - } - - 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) { - debug_input(self.data.read()); - } - } - - pub fn send(&mut self, data: u8) { - match data { - 8 | 0x7F => { - while ! self.line_sts().contains(OUTPUT_EMPTY) {} - self.data.write(8); - while ! self.line_sts().contains(OUTPUT_EMPTY) {} - self.data.write(b' '); - while ! self.line_sts().contains(OUTPUT_EMPTY) {} - self.data.write(8); - }, - _ => { - while ! self.line_sts().contains(OUTPUT_EMPTY) {} - self.data.write(data); - } - } - } -} - -impl Write for SerialPort { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - for byte in s.bytes() { - self.send(byte); - } - - Ok(()) - } -} diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs index ab75124..ff4f79c 100644 --- a/src/arch/x86_64/macros.rs +++ b/src/arch/x86_64/macros.rs @@ -1,3 +1,20 @@ +/// Print to console +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + use core::fmt::Write; + let _ = write!($crate::arch::device::serial::COM1.lock(), $($arg)*); + }); +} + +/// Print with new line to console +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + /// Create an interrupt function that can safely run rust code #[macro_export] macro_rules! interrupt { diff --git a/src/devices/mod.rs b/src/devices/mod.rs new file mode 100644 index 0000000..9dc8d5b --- /dev/null +++ b/src/devices/mod.rs @@ -0,0 +1 @@ +pub mod uart_16550; \ No newline at end of file diff --git a/src/devices/uart_16550.rs b/src/devices/uart_16550.rs new file mode 100644 index 0000000..8dfb356 --- /dev/null +++ b/src/devices/uart_16550.rs @@ -0,0 +1,122 @@ +use core::fmt::{self, Write}; + +use scheme::debug::debug_input; +use syscall::io::{Io, Pio, Mmio, ReadOnly}; + +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 + } +} + +#[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, +} + +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) { + debug_input(self.data.read()); + } + } + + pub fn send(&mut self, data: u8) { + match data { + 8 | 0x7F => { + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + self.data.write(8); + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + self.data.write(b' '); + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + self.data.write(8); + }, + _ => { + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + self.data.write(data); + } + } + } +} + +impl> Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + for byte in s.bytes() { + self.send(byte); + } + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index aaedb09..33e746a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,9 +42,10 @@ pub use consts::*; /// Shared data structures pub mod common; -/// Macros like print, println, and interrupt +/// Architecture-dependent stuff #[macro_use] -pub mod macros; +pub mod arch; +pub use arch::*; /// Constants like memory locations pub mod consts; @@ -52,14 +53,12 @@ pub mod consts; /// ACPI table parsing mod acpi; -/// Architecture-dependent stuff -mod arch; -#[cfg(target_arch = "x86_64")] -pub use arch::x86_64::*; - /// Context management pub mod context; +/// Architecture-independent devices +pub mod devices; + /// ELF file parsing pub mod elf; diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index beaef43..0000000 --- a/src/macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -/// Print to console -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - use core::fmt::Write; - let _ = write!($crate::device::serial::COM1.lock(), $($arg)*); - }); -} - -/// Print with new line to console -#[macro_export] -macro_rules! println { - () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -}