diff --git a/Cargo.toml b/Cargo.toml index 872dd9b8..46f8254b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ crate-type = ["staticlib"] [dependencies] rlibc = "*" +spin = "*" diff --git a/src/lib.rs b/src/lib.rs index bbf11c0a..686f2d24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,25 +13,19 @@ // limitations under the License. #![feature(no_std, lang_items)] +#![feature(const_fn, unique, core_str_ext)] #![no_std] extern crate rlibc; +extern crate spin; + +#[macro_use] +mod vga_buffer; #[no_mangle] pub extern fn rust_main() { // ATTENTION: we have a very small stack and no guard page - - let hello = b"Hello World!"; - let color_byte = 0x1f; // white foreground, blue background - - let mut hello_colored = [color_byte; 24]; - for (i, char_byte) in hello.into_iter().enumerate() { - hello_colored[i*2] = *char_byte; - } - - // write `Hello World!` to the center of the VGA text buffer - let buffer_ptr = (0xb8000 + 1988) as *mut _; - unsafe { *buffer_ptr = hello_colored }; + println!("Hello World{}", "!"); loop{} } diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs new file mode 100644 index 00000000..e16c1647 --- /dev/null +++ b/src/vga_buffer.rs @@ -0,0 +1,121 @@ +use core::ptr::Unique; +use core::fmt; +use spin::Mutex; + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +pub static WRITER: Mutex = Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::LightGreen, Color::Black), + buffer: unsafe{Unique::new(0xb8000 as *mut _)}, +}); + +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +macro_rules! print { + ($($arg:tt)*) => ({ + use core::fmt::Write; + $crate::vga_buffer::WRITER.lock().write_fmt(format_args!($($arg)*)).unwrap(); + }); +} + +#[allow(dead_code)] +#[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, +} + +pub struct Writer { + column_position: usize, + color_code: ColorCode, + buffer: Unique, +} + +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; + + self.buffer().chars[row][col] = ScreenChar { + ascii_character: byte, + color_code: self.color_code, + }; + self.column_position += 1; + } + } + } + + fn buffer(&mut self) -> &mut Buffer { + unsafe{self.buffer.get_mut()} + } + + fn new_line(&mut self) { + for row in 0..(BUFFER_HEIGHT-1) { + let buffer = self.buffer(); + buffer.chars[row] = buffer.chars[row + 1] + } + self.clear_row(BUFFER_HEIGHT-1); + self.column_position = 0; + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: ' ' as u8, + color_code: self.color_code, + }; + self.buffer().chars[row] = [blank; BUFFER_WIDTH]; + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> ::core::fmt::Result { + for byte in s.bytes() { + self.write_byte(byte) + } + Ok(()) + } +} + +#[derive(Clone, Copy)] +struct ColorCode(u8); + +impl ColorCode { + const fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} + +#[derive(Clone, Copy)] +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +struct Buffer { + chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], +}