diff --git a/src/interrupts.rs b/src/interrupts.rs index 13c54728..14623462 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,6 +1,7 @@ -// LLVM throws an error if a function with the -// x86-interrupt calling convention is compiled -// for a Windows system. +// The x86-interrupt calling convention leads to the following LLVM error +// when compiled for a Windows target: "offset is not a multiple of 16". This +// happens for example when running `cargo test` on Windows. To avoid this +// problem we skip compilation of this module on Windows. #![cfg(not(windows))] use crate::{gdt, println}; diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 9f0a1996..211d9664 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -4,6 +4,9 @@ use spin::Mutex; use volatile::Volatile; lazy_static! { + /// A global `Writer` instance that can be used for printing to the VGA text buffer. + /// + /// Used by the `print!` and `println!` macros. pub static ref WRITER: Mutex = Mutex::new(Writer { column_position: 0, color_code: ColorCode::new(Color::Yellow, Color::Black), @@ -11,6 +14,7 @@ lazy_static! { }); } +/// The standard color palette in VGA text mode. #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -33,15 +37,18 @@ pub enum Color { White = 15, } +/// A combination of a foreground and a background color. #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ColorCode(u8); impl ColorCode { + /// Create a new `ColorCode` with the given foreground and background colors. fn new(foreground: Color, background: Color) -> ColorCode { ColorCode((background as u8) << 4 | (foreground as u8)) } } +/// A screen character in the VGA text buffer, consisting of an ASCII character and a `ColorCode`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(C)] struct ScreenChar { @@ -49,13 +56,20 @@ struct ScreenChar { color_code: ColorCode, } +/// The height of the text buffer (normally 25 lines). const BUFFER_HEIGHT: usize = 25; +/// The width of the text buffer (normally 80 columns). const BUFFER_WIDTH: usize = 80; +/// A structure representing the VGA text buffer. struct Buffer { chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], } +/// A writer type that allows writing ASCII bytes and strings to an underlying `Buffer`. +/// +/// Wraps lines at `BUFFER_WIDTH`. Supports newline characters and implements the +/// `core::fmt::Write` trait. pub struct Writer { column_position: usize, color_code: ColorCode, @@ -63,6 +77,9 @@ pub struct Writer { } impl Writer { + /// Writes an ASCII byte to the buffer. + /// + /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. pub fn write_byte(&mut self, byte: u8) { match byte { b'\n' => self.new_line(), @@ -84,7 +101,12 @@ impl Writer { } } - pub fn write_string(&mut self, s: &str) { + /// Writes the given ASCII string to the buffer. + /// + /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. Does **not** + /// support strings with non-ASCII characters, since they can't be printed in the VGA text + /// mode. + fn write_string(&mut self, s: &str) { for byte in s.bytes() { match byte { // printable ASCII byte or newline @@ -95,6 +117,7 @@ impl Writer { } } + /// Shifts all lines one line up and clears the last row. fn new_line(&mut self) { for row in 1..BUFFER_HEIGHT { for col in 0..BUFFER_WIDTH { @@ -106,6 +129,7 @@ impl Writer { self.column_position = 0; } + /// Clears a row by overwriting it with blank characters. fn clear_row(&mut self, row: usize) { let blank = ScreenChar { ascii_character: b' ', @@ -124,17 +148,20 @@ impl fmt::Write for Writer { } } +/// Like the `print!` macro in the standard library, but prints to the VGA text buffer. #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*))); } +/// Like the `println!` macro in the standard library, but prints to the VGA text buffer. #[macro_export] macro_rules! println { () => ($crate::print!("\n")); ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); } +/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance. #[doc(hidden)] pub fn _print(args: fmt::Arguments) { use core::fmt::Write;