diff --git a/arch/x86_64/src/device/display.rs b/arch/x86_64/src/device/display.rs index 1a978d3..22542a1 100644 --- a/arch/x86_64/src/device/display.rs +++ b/arch/x86_64/src/device/display.rs @@ -43,6 +43,7 @@ pub struct VBEModeInfo { } pub static DISPLAY: Mutex> = Mutex::new(None); +static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font"); pub unsafe fn init(active_table: &mut ActivePageTable) { active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE); @@ -108,6 +109,7 @@ impl Display { } } + /// Draw a rectangle pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { let start_y = cmp::min(self.height - 1, y); let end_y = cmp::min(self.height, y + h); @@ -123,4 +125,25 @@ impl Display { } } } + + /// Draw a character + pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) { + if x + 8 <= self.width && y + 16 <= self.height { + let mut offset = y * self.width + x; + + let font_i = 16 * (character as usize); + if font_i + 16 <= FONT.len() { + for row in 0..16 { + let row_data = FONT[font_i + row]; + for col in 0..8 { + if (row_data >> (7 - col)) & 1 == 1 { + self.data[offset + col] = color; + } + } + + offset += self.width; + } + } + } + } } diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs index bfac385..9ca32d7 100644 --- a/arch/x86_64/src/device/mod.rs +++ b/arch/x86_64/src/device/mod.rs @@ -2,10 +2,12 @@ use paging::ActivePageTable; pub mod display; pub mod ps2; +pub mod serial; pub unsafe fn init(active_table: &mut ActivePageTable){ - display::init(active_table); + serial::init(); ps2::init(); + display::init(active_table); } pub unsafe fn init_ap(active_table: &mut ActivePageTable) { diff --git a/arch/x86_64/src/device/ps2.rs b/arch/x86_64/src/device/ps2.rs index 3a07fe4..83a7d88 100644 --- a/arch/x86_64/src/device/ps2.rs +++ b/arch/x86_64/src/device/ps2.rs @@ -15,6 +15,10 @@ bitflags! { const INPUT_FULL = 1 << 1, const SYSTEM = 1 << 2, const COMMAND = 1 << 3, + // Chipset specific + const KEYBOARD_LOCK = 1 << 4, + // Chipset specific + const SECOND_OUTPUT_FULL = 1 << 5, const TIME_OUT = 1 << 6, const PARITY = 1 << 7 } @@ -26,10 +30,12 @@ bitflags! { const SECOND_INTERRUPT = 1 << 1, const POST_PASSED = 1 << 2, // 1 << 3 should be zero + const CONFIG_RESERVED_3 = 1 << 3, const FIRST_DISABLED = 1 << 4, const SECOND_DISABLED = 1 << 5, const FIRST_TRANSLATE = 1 << 6, // 1 << 7 should be zero + const CONFIG_RESERVED_7 = 1 << 7, } } diff --git a/arch/x86_64/src/device/serial.rs b/arch/x86_64/src/device/serial.rs new file mode 100644 index 0000000..848e82b --- /dev/null +++ b/arch/x86_64/src/device/serial.rs @@ -0,0 +1,118 @@ +use core::fmt::{self, Write}; +use spin::Mutex; + +use io::{Io, Pio, ReadOnly}; + +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 + } +} + +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 int_en(&self) -> IntEnFlags { + IntEnFlags::from_bits_truncate(self.int_en.read()) + } + + fn line_sts(&self) -> LineStsFlags { + LineStsFlags::from_bits_truncate(self.line_sts.read()) + } + + fn write(&mut self, data: u8) { + while ! self.line_sts().contains(OUTPUT_EMPTY) {} + self.data.write(data) + } + + fn init(&mut self) { + 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); + } + + pub fn on_receive(&mut self) { + let data = self.data.read(); + write!(self, "SERIAL {:X}\n", data); + } +} + +impl Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + for byte in s.bytes() { + self.write(byte); + + if byte == 8 { + self.write(b' '); + self.write(8); + } + } + + Ok(()) + } +} + +pub struct SerialConsole; + +impl Write for SerialConsole { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + COM1.lock().write_str(s); + + Ok(()) + } +} diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index 3a20098..ff91cbf 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -1,6 +1,7 @@ use x86::io; use device::ps2::PS2; +use device::serial::{COM1, COM2}; #[inline(always)] unsafe fn master_ack() { @@ -33,12 +34,12 @@ interrupt!(cascade, { }); interrupt!(com2, { - print!("COM2\n"); + COM2.lock().on_receive(); master_ack(); }); interrupt!(com1, { - print!("COM1\n"); + COM1.lock().on_receive(); master_ack(); }); diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 856eec8..f99030b 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -21,7 +21,7 @@ extern crate x86; macro_rules! print { ($($arg:tt)*) => ({ use core::fmt::Write; - let _ = write!($crate::serial::SerialConsole, $($arg)*); + let _ = write!($crate::device::serial::SerialConsole, $($arg)*); }); } @@ -149,8 +149,5 @@ pub mod paging; /// Panic pub mod panic; -/// Serial driver and print! support -pub mod serial; - /// Initialization and start function pub mod start; diff --git a/arch/x86_64/src/serial.rs b/arch/x86_64/src/serial.rs deleted file mode 100644 index 2203084..0000000 --- a/arch/x86_64/src/serial.rs +++ /dev/null @@ -1,45 +0,0 @@ -use core::fmt; -use spin::Mutex; - -use super::io::{Io, Pio}; - -static SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); - -struct SerialPort { - status: Pio, - data: Pio -} - -impl SerialPort { - pub const fn new() -> SerialPort { - SerialPort { - status: Pio::new(0x3F8 + 5), - data: Pio::new(0x3F8) - } - } - - pub fn write(&mut self, bytes: &[u8]) { - for byte in bytes.iter() { - while !self.status.readf(0x20) {} - self.data.write(*byte); - - if *byte == 8 { - while !self.status.readf(0x20) {} - self.data.write(0x20); - - while !self.status.readf(0x20) {} - self.data.write(8); - } - } - } -} - -pub struct SerialConsole; - -impl fmt::Write for SerialConsole { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - SERIAL_PORT.lock().write(s.as_bytes()); - - Ok(()) - } -} diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index 987bb7e..27be190 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -197,7 +197,7 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! { if let Some(ref mut display) = *device::display::DISPLAY.lock() { let width = display.width; - display.rect(0, ap_number * 32, width, 16, 0xFF00); + display.char(0, ap_number * 16, (ap_number as u8 + b'0') as char, 0xFF00); } kmain_ap(ap_number); diff --git a/res/unifont.font b/res/unifont.font new file mode 100644 index 0000000..01173fc Binary files /dev/null and b/res/unifont.font differ