diff --git a/Cargo.lock b/Cargo.lock index dc8e991..5c4e104 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,8 @@ name = "sparkle_os" version = "0.1.0" dependencies = [ "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "x86 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -179,6 +181,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "spin" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "volatile" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "x86" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -214,4 +226,6 @@ dependencies = [ "checksum serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97b18e9e53de541f11e497357d6c5eaeb39f0cb9c8734e274abe4935f6991fa" "checksum serde_json 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5aaee47e038bf9552d30380d3973fff2593ee0a76d81ad4c581f267cdcadf36" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" +"checksum spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d16a26e2b789f86aabddbe91cb82ee2e822beb8a59840d631941b625ef77e53" +"checksum volatile 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6633c5250f16598f92b48272265ce9f8179447f702f0ba0cb640c5be6537b0c0" "checksum x86 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ada1976e1004a0b5999beb7403541af96637e8f439b97d86c8c9abef2e0e7d19" diff --git a/Cargo.toml b/Cargo.toml index 4cd382b..8c851f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,6 @@ crate-type = ["staticlib"] [dependencies] rlibc = "1.0" -x86 = "0.8" \ No newline at end of file +spin = "0.4.5" +volatile = "0.2" +x86 = "0.8" diff --git a/src/arch/mod.rs b/src/arch/mod.rs new file mode 100644 index 0000000..0bffdbe --- /dev/null +++ b/src/arch/mod.rs @@ -0,0 +1 @@ +pub mod x86_64; \ No newline at end of file diff --git a/src/arch/x86_64/device/mod.rs b/src/arch/x86_64/device/mod.rs new file mode 100644 index 0000000..f140e2a --- /dev/null +++ b/src/arch/x86_64/device/mod.rs @@ -0,0 +1 @@ +pub mod vga_console; diff --git a/src/arch/x86_64/device/vga_console.rs b/src/arch/x86_64/device/vga_console.rs new file mode 100644 index 0000000..8267d7c --- /dev/null +++ b/src/arch/x86_64/device/vga_console.rs @@ -0,0 +1,155 @@ +use core::fmt; +use core::ptr::Unique; +use spin::Mutex; +use volatile::Volatile; + +pub static WRITER: Mutex = Mutex::new(Writer { + column_pos: 0, row_pos: 0, + style: CharStyle::new(Color::Cyan, Color::DarkGray), + buffer: unsafe {Unique::new(0xb8000 as *mut _)}, +}); + +#[allow(dead_code)] +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum Color { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + Pink = 13, + Yellow = 14, + White = 15, +} + +#[derive(Clone, Copy, Debug)] +pub struct CharStyle(u8); +impl CharStyle { + const fn new(foreground: Color, background: Color) -> CharStyle { + CharStyle((background as u8) << 4 | (foreground as u8)) + } +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +struct VgaChar { + ascii_char: u8, + style: CharStyle, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +/// Shadows the actual VGA text-mode buffer at 0xb8000. +struct Buffer { + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +/// Abstraction layer used to write into the VGA text buffer +pub struct Writer { + /// Current position of the 'write cursor' + row_pos: usize, column_pos: usize, + /// Current style we're writing with + style: CharStyle, + /// This is set up on initialization to shadow `0xb8000`, the VGA text-mode buffer. + buffer: Unique, +} + +#[allow(dead_code)] +impl Writer { + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.new_line(), + byte => { + if self.column_pos >= BUFFER_WIDTH {self.new_line();} + + let row = self.row_pos; + let col = self.column_pos; + let style = self.style; + + self.buffer().chars[row][col].write(VgaChar { + ascii_char: byte, + style: style, + }); + + self.column_pos += 1; + } + } + } + + pub fn write_byte_at(&mut self, byte: u8, row: usize, col: usize) { + self.row_pos = row; self.column_pos = col; + let style = self.style; + + self.buffer().chars[row][col].write(VgaChar {ascii_char: byte, style: style}); + } + + pub fn clear_screen(&mut self) { + let clear_style = VgaChar {ascii_char: b' ', style: self.style}; + for row in 0..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + self.buffer().chars[row][col].write(clear_style); + } + } + } + + pub fn set_style(&mut self, style: CharStyle) { + self.style = style; + } + + pub fn get_style(&self) -> CharStyle { + self.style + } + + fn new_line(&mut self) { + self.column_pos = 0; + self.row_pos += 1; + + if self.row_pos >= BUFFER_HEIGHT { + self.scroll(); + } + } + + fn clear_row(&mut self, row: usize) { + let clear_style = VgaChar {ascii_char: b' ', style: self.style}; + for col in 0..BUFFER_WIDTH { + self.buffer().chars[row][col].write(clear_style); + } + } + + fn scroll(&mut self){ + for row in 0..(BUFFER_HEIGHT - 1) { + for col in 0..BUFFER_WIDTH { + let c = self.buffer().chars[row + 1][col].read(); + self.buffer().chars[row][col].write(c); + } + } + + self.clear_row(BUFFER_HEIGHT - 1); + self.column_pos = 0; + self.row_pos = BUFFER_HEIGHT - 1; + } + + fn buffer(&mut self) -> &mut Buffer { + unsafe { self.buffer.as_mut() } + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + self.write_byte(byte); + } + + Ok(()) + } +} diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs new file mode 100644 index 0000000..91f2d96 --- /dev/null +++ b/src/arch/x86_64/mod.rs @@ -0,0 +1 @@ +pub mod device; \ No newline at end of file diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..a59e561 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,20 @@ +use core::fmt; + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + $crate::macros::print(format_args!($($arg)*)); + }); +} + +pub fn print(args: fmt::Arguments) { + use core::fmt::Write; + let _ = ::arch::x86_64::device::vga_console::WRITER.lock().write_fmt(args); +} + +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +}