diff --git a/ableos/src/arch/x86_64/init.rs b/ableos/src/arch/x86_64/init.rs index 28a3290..cd228fa 100644 --- a/ableos/src/arch/x86_64/init.rs +++ b/ableos/src/arch/x86_64/init.rs @@ -31,7 +31,7 @@ pub fn init() { Capabilities::empty(), High, "".to_string(), - StdIO::new(crate::stdio::Device::VTerm), + StdIO::new("null".to_string()), ); scheduler.add_process(process_0); diff --git a/ableos/src/devices/character_devs/mod.rs b/ableos/src/devices/character_devs/mod.rs index 9a2f294..50c9169 100644 --- a/ableos/src/devices/character_devs/mod.rs +++ b/ableos/src/devices/character_devs/mod.rs @@ -1,5 +1,6 @@ pub mod dev_null; pub mod dev_unicode; + pub mod dev_zero; pub use kernel::device_interface::character::CharacterDevice; diff --git a/ableos/src/devices/dev_vterm.rs b/ableos/src/devices/dev_vterm.rs new file mode 100644 index 0000000..40c348d --- /dev/null +++ b/ableos/src/devices/dev_vterm.rs @@ -0,0 +1,245 @@ +// ! A virtual terminal device. + +use kernel::device_interface::character::CharacterDevice; + +use core::ops::Not; +use shadeable::pixel_format::Rgba64; +pub const VTERM_HEIGHT: u32 = 40; +pub const VTERM_WIDTH: u32 = 100; +/// Fg and bg colors for vterm +pub type ColorCharacter = (Rgba64, Rgba64); +/// A vterm representation of a character +#[derive(Debug, Clone, Copy)] +pub struct VtermCharacter { + pub character: char, + // + pub style: Style, + // + pub char_color: ColorCharacter, +} + +#[derive(Default, Debug, Clone, Copy)] + +pub struct Style(pub u8); +impl Style { + pub fn bold(&self) -> bool { + (self.0 & 0x01) > 0 + } + pub fn underlined(&self) -> bool { + (self.0 & 0x02) > 0 + } + pub fn italic(&self) -> bool { + (self.0 & 0x04) > 0 + } + pub fn blinking(&self) -> bool { + (self.0 & 0x08) > 0 + } + pub fn reversed(&self) -> bool { + (self.0 & 0x10) > 0 + } + pub fn struck(&self) -> bool { + (self.0 & 0x20) > 0 + } + #[must_use] + pub fn set_bold(mut self, v: bool) -> Self { + if v { + self.0 |= 0x01; + } else { + self.0 &= 0x01u8.not(); + } + self + } + #[must_use] + pub fn set_underlined(mut self, v: bool) -> Self { + if v { + self.0 |= 0x02; + } else { + self.0 &= 0x02u8.not(); + } + self + } + #[must_use] + pub fn set_italic(mut self, v: bool) -> Self { + if v { + self.0 |= 0x04; + } else { + self.0 &= 0x04u8.not(); + } + self + } + #[must_use] + pub fn set_blinking(mut self, v: bool) -> Self { + if v { + self.0 |= 0x08; + } else { + self.0 &= 0x08u8.not(); + } + self + } + #[must_use] + pub fn set_reversed(mut self, v: bool) -> Self { + if v { + self.0 |= 0x10; + } else { + self.0 &= 0x10u8.not(); + } + self + } + #[must_use] + pub fn set_struck(mut self, v: bool) -> Self { + if v { + self.0 |= 0x20; + } else { + self.0 &= 0x20u8.not(); + } + self + } +} +#[derive(Debug)] +pub struct VTerm { + iid: u32, + pub characters: [[VtermCharacter; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize], + /// The internal representation of the vterm + style: Style, + /// The cursor position in layout x,y + cursor_position: (u32, u32), + pub cursor_visible: bool, + key_buff: Vec, +} +impl Default for VTerm { + fn default() -> Self { + VTerm { + iid: 0, + characters: [[VtermCharacter { + character: 0x00 as char, + char_color: (0xff_ff_ff_ff, 0x00_00_00_00), + style: Style::default(), + }; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize], + cursor_position: (0, 0), + cursor_visible: true, + style: Style::default(), + key_buff: vec![], + } + } +} + +/// The primitive interface for a vterm +impl VTerm { + pub fn new() -> Self { + let mut vterm = VTerm::default(); + let mut vtc = VIRTUAL_TERMINAL_COUNT.load(Ordering::Relaxed); + vterm.iid = vtc; + vtc += 1; + VIRTUAL_TERMINAL_COUNT.store(vtc, Ordering::Relaxed); + + vterm + } + /// Set the vterm cursor to the given position + pub fn set_cursor_position(&mut self, x: u32, y: u32) { + if x > VTERM_WIDTH { + self.cursor_position.0 = VTERM_WIDTH; + error!("Cursor x position out of bounds"); + } else { + self.cursor_position.0 = x; + } + if y > VTERM_HEIGHT { + error!("Cursor y position out of bounds"); + self.cursor_position.1 = VTERM_HEIGHT; + } else { + self.cursor_position.1 = y; + } + } + /// Set the vterm style + pub fn set_vterm_style(&mut self, style: Style) { + self.style = style; + } +} + +impl CharacterDevice for VTerm { + fn can_read(&self) -> bool { + true + } + + fn can_write(&self) -> bool { + true + } + + fn read_char(&mut self) -> Option { + if let Some(c) = self.key_buff.pop() { + return Some(c); + } + None + } + + fn write_char(&mut self, c: char) -> bool { + match c { + '\n' => { + self.cursor_position.1 += 1; + self.cursor_position.0 = 0; + return true; + } + '\r' => { + self.cursor_position.0 = 0; + return true; + } + '\t' => { + self.cursor_position.0 += 4; + return true; + } + '\x08' => { + self.cursor_position.0 -= 1; + self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize] + .character = ' '; + return true; + } + /// This is a form feed, which is used to clear the screen + '\x0c' => { + self.characters = [[VtermCharacter { + character: ' ', + char_color: (0xff_ff_ff_ff, 0x00_00_00_00), + style: Style::default(), + }; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize]; + return true; + } + + _ => { + self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize] + .character = c; + self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize] + .char_color = (0xff_ff_ff_ff, 0x00_00_00_00); + self.characters[self.cursor_position.1 as usize][self.cursor_position.0 as usize] + .style = self.style; + + if self.cursor_position.0 < VTERM_WIDTH { + self.cursor_position.0 += 1; + return true; + } else { + self.cursor_position.0 = 0; + self.cursor_position.1 += 1; + return true; + } + } + } + } + + fn reset(&mut self) { + self.characters = [[VtermCharacter { + character: ' ', + char_color: (0xff_ff_ff_ff, 0x00_00_00_00), + style: Style::default(), + }; VTERM_WIDTH as usize]; VTERM_HEIGHT as usize]; + self.cursor_position = (0, 0); + self.cursor_visible = true; + self.style = Style::default(); + } + + fn initialize(&mut self) -> bool { + true + } +} + +lazy_static::lazy_static! { + pub static ref VIRTUAL_TERMINAL_COUNT: AtomicU32 = AtomicU32::new(0); +} +use core::sync::atomic::AtomicU32; +use core::sync::atomic::Ordering; diff --git a/ableos/src/devices/mod.rs b/ableos/src/devices/mod.rs index fb6d004..10d61a4 100644 --- a/ableos/src/devices/mod.rs +++ b/ableos/src/devices/mod.rs @@ -3,13 +3,14 @@ pub mod id; pub mod pci_inner; use hashbrown::HashMap; - +mod dev_vterm; +use crate::devices::dev_vterm::VTerm; use kernel::device_interface::character::CharacterDevice; - // FIXME: This is a hack to hold a device. // #[derive(Debug)] pub enum Device { Character(Box), + Vterm(VTerm), } unsafe impl Sync for Device {} unsafe impl Send for Device {} @@ -31,6 +32,7 @@ impl DeviceTable { next_read_char: 0x00 as char, })), ); + table.insert("kvterm".to_string(), Vterm(VTerm::new())); DeviceTable { devices: table } } } diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 395cb32..f38b84c 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -1,13 +1,15 @@ use acpi::AcpiTables; +use kernel::device_interface::character::CharacterDevice; +use crate::devices::DEVICE_TABLE; use crate::rhai_shell::shell; use crate::stdio::StdIO; + +use crate::devices::Device::Vterm; + /// Experimental scratchpad for testing. pub fn scratchpad() { - let mut stdio = StdIO::new(crate::stdio::Device::Serial); - stdio.write(); - shell(); } diff --git a/ableos/src/stdio.rs b/ableos/src/stdio.rs index 367909f..c49776e 100644 --- a/ableos/src/stdio.rs +++ b/ableos/src/stdio.rs @@ -1,30 +1,42 @@ -use core::fmt::Arguments; -use core::fmt::Error; -use core::fmt::Write; +use { + crate::{ + devices::Device::{Character, Vterm}, + kprintln, + }, + core::fmt::{Arguments, Error, Write}, + kernel::device_interface::character::CharacterDevice, +}; -use crate::kprintln; - -#[derive(Debug, Clone, Copy)] -pub enum Device { - VTerm, - Serial, -} -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct StdIO { - device: Device, + device: String, } impl StdIO { - pub fn new(device: Device) -> StdIO { + pub fn new(device: String) -> StdIO { StdIO { device } } - pub fn write(&mut self) { - match self.device { - Device::VTerm => { - println!("Hello, world!"); + pub fn write(&mut self, args: Arguments) -> Result<(), Error> { + use crate::devices::DEVICE_TABLE; + let mut dt = DEVICE_TABLE.lock(); + let key_device = dt.devices.get_mut(&self.device).unwrap(); + + match key_device { + Character(dev) => { + let mut buf = String::new(); + write!(buf, "{}", args).unwrap(); + for c in buf.chars() { + dev.write_char(c); + } + Ok(()) } - Device::Serial => { - serial_println!("Hello, world!"); + Vterm(vterm) => { + let mut buf = String::new(); + write!(buf, "{}", args).unwrap(); + for c in buf.chars() { + vterm.write_char(c); + } + Ok(()) } } }