diff --git a/Cargo.lock b/Cargo.lock index 339dd95..a17d608 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,4 +1,38 @@ +[[package]] +name = "lazy_static" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "os_boot" version = "0.1.0" +dependencies = [ + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] +[[package]] +name = "spin" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "volatile" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" +"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" +"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8" diff --git a/Cargo.toml b/Cargo.toml index 1faad45..2770614 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,12 @@ version = "0.1.0" authors = ["ishanjain28 "] [dependencies] +volatile = "0.2.3" +spin = "0.4.6" + +[dependencies.lazy_static] +version = "1.0" +features = ["spin_no_std"] [package.metadata.bootimage] default-target = "x86_64-os.json" diff --git a/src/main.rs b/src/main.rs index 792c807..5eb9520 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,17 @@ #![no_std] // don't include rust std lib #![no_main] // disable all rust entry point +extern crate volatile; +extern crate spin; + +#[macro_use] +extern crate lazy_static; + +mod vga_buffer; + +use core::fmt::Write; use core::panic::PanicInfo; +use vga_buffer::{Buffer, Color, ColorCode, Writer}; /// This function is called on panic. #[panic_implementation] @@ -11,18 +21,12 @@ pub fn panic(_info: &PanicInfo) -> ! { loop {} } -static HELLO: &[u8] = b"Hello World!"; - #[no_mangle] // don't change the name of function in symbol table pub extern "C" fn _start() -> ! { - let vga_buffer = 0xb8000 as *mut u8; - - for (i, &byte) in HELLO.iter().enumerate() { - unsafe { - *vga_buffer.offset(i as isize * 2) = byte; - *vga_buffer.offset(i as isize * 2 + 1) = 0xb; - } - } + use core::fmt::Write; + vga_buffer::WRITER.lock().write_str("Hello again").unwrap(); + write!(vga_buffer::WRITER.lock(), ", some numbers: {} {}", 42, 1.337).unwrap(); loop {} } + diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs new file mode 100644 index 0000000..a2ca9c8 --- /dev/null +++ b/src/vga_buffer.rs @@ -0,0 +1,133 @@ +use core::fmt; +use volatile::Volatile; +use spin::Mutex; + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[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, +} + +// represents a color by combining foreground and background +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct ColorCode(u8); + +impl ColorCode { + pub fn new(foreground: Color, background: Color) -> ColorCode { + // foreground/background use 4 bits + // u8 is used because there is no u4 in rust + // The 4 most significant bits in ColorCode store background + // and 4 least significant bits store foreground color + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Copy)] +#[repr(C)] +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +// This represents the vga buffer of size 25 * 80. +pub struct Buffer { + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +pub struct Writer { + pub column_position: usize, + pub color_code: ColorCode, + pub buffer: &'static mut Buffer, +} + +lazy_static! { + pub static ref WRITER: Mutex = Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + }); +} + +impl Writer { + 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; + + self.buffer.chars[row][col].write(ScreenChar { + ascii_character: byte, + color_code: color_code, + }); + + self.column_position += 1; + } + } + } + + pub fn write_string(&mut self, ip: &str) { + for byte in ip.bytes() { + match byte { + 0x20...0x7e | b'\n' => self.write_byte(byte), + _ => self.write_byte(0xfe), + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 1..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.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 { + self.buffer.chars[row][col].write(blank); + } + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + + Ok(()) + } +}