From 188a08c3a340005d59d497e836993cb9349c9cbe Mon Sep 17 00:00:00 2001 From: Christian Cunningham Date: Mon, 22 Aug 2022 20:54:54 -0700 Subject: Initial state --- src/vga/buffer.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/vga/buffer.rs (limited to 'src/vga/buffer.rs') diff --git a/src/vga/buffer.rs b/src/vga/buffer.rs new file mode 100644 index 0000000..34c665d --- /dev/null +++ b/src/vga/buffer.rs @@ -0,0 +1,157 @@ +use super::*; +use core::fmt; +use volatile::Volatile; +use crate::sync::NullLock; +use crate::sync::interface::Mutex; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +#[repr(transparent)] +struct Buffer { + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +pub struct VgaWriter { + column_position: usize, + color_code: ColorCode, + buffer: Option<&'static mut Buffer>, +} + +impl VgaWriter { + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.new_line(), + byte => { + if self.column_position >= BUFFER_WIDTH { + self.new_line(); + } + + let row = BUFFER_HEIGHT - 1; + let col = self.column_position; + + let color_code = self.color_code; + if let Some(buffer) = &mut self.buffer { + buffer.chars[row][col].write(ScreenChar { +ascii_character: byte, +color_code, +}); + } + self.column_position += 1; + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + if let Some(buffer) = &mut self.buffer { + let character = buffer.chars[row][col].read(); + buffer.chars[row - 1][col].write(character); + } + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.column_position = 0; + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: b' ', + color_code: self.color_code, + }; + for col in 0..BUFFER_WIDTH { + if let Some(buffer) = &mut self.buffer { + buffer.chars[row][col].write(blank); + } + } + } + + pub fn write_string(&mut self, s: &str) { + for byte in s.bytes() { + match byte { + // printable ASCII byte or newline + 0x20..=0x7e | b'\n' => self.write_byte(byte), + // not part of printable ASCII range + _ => self.write_byte(0xfe), + } + + } + } +} + +impl NullLock { + #[allow(dead_code)] + pub fn write_byte(&self, byte: u8) { + self.lock(|writer| { + writer.write_byte(byte); + }); + } + + #[allow(dead_code)] + fn new_line(&self) { + self.lock(|writer| { + writer.new_line(); + }); + } + + #[allow(dead_code)] + fn clear_row(&self, row: usize) { + self.lock(|writer| { + writer.clear_row(row); + }); + } + + pub fn write_string(&self, s: &str) { + self.lock(|writer| { + writer.write_string(s); + }); + } +} + +impl fmt::Write for VgaWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + Ok(()) + } +} + +impl NullLock { + pub fn init(&self) { + self.lock(|writer| { + writer.buffer = Some(unsafe { &mut *(0xb8000 as *mut Buffer) }); + }) + } +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + WRITER.lock(|writer| { + writer.write_fmt(args).unwrap(); + }); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::vga::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); +} + +pub static WRITER: NullLock = NullLock::new(VgaWriter { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: None, +}); -- cgit v1.2.1