From 49fd8926a5d03c58d3587bddbf997bdc88dbfd85 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 14:12:49 +0200 Subject: [PATCH 1/7] Add a VGA buffer module skeleton It contains basic types for colors, screen characters, and the buffer itself. --- src/lib.rs | 3 +++ src/vga_buffer.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/vga_buffer.rs diff --git a/src/lib.rs b/src/lib.rs index bbf11c0a..29afba64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,10 +13,13 @@ // limitations under the License. #![feature(no_std, lang_items)] +#![feature(const_fn)] #![no_std] extern crate rlibc; +mod vga_buffer; + #[no_mangle] pub extern fn rust_main() { // ATTENTION: we have a very small stack and no guard page diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs new file mode 100644 index 00000000..efc42ed7 --- /dev/null +++ b/src/vga_buffer.rs @@ -0,0 +1,39 @@ +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +#[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, +} + +struct ColorCode(u8); + +impl ColorCode { + const fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} + +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +struct Buffer { + chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], +} From ab464b107da156097d3e55a2cadc7f21179b9018 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 14:24:45 +0200 Subject: [PATCH 2/7] Add a basic writer type to print single bytes It prints always to the last line and shifts lines up on newline or line wrap. To easily shift lines up, we make the ColorCode and ScreenChar types Copy. --- src/lib.rs | 2 +- src/vga_buffer.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 29afba64..8cbf9724 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ // limitations under the License. #![feature(no_std, lang_items)] -#![feature(const_fn)] +#![feature(const_fn, unique)] #![no_std] extern crate rlibc; diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index efc42ed7..46c5f73a 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -1,3 +1,5 @@ +use core::ptr::Unique; + const BUFFER_HEIGHT: usize = 25; const BUFFER_WIDTH: usize = 80; @@ -21,6 +23,55 @@ pub enum Color { 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]; + } +} + +#[derive(Clone, Copy)] struct ColorCode(u8); impl ColorCode { @@ -29,6 +80,7 @@ impl ColorCode { } } +#[derive(Clone, Copy)] struct ScreenChar { ascii_character: u8, color_code: ColorCode, From 4668acb09e1c74c7717ec28f0c94a2bd1b003aab Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 15:52:33 +0200 Subject: [PATCH 3/7] Add a public static writer Since `unsafe const` aren't allowed yet, we temorary add a custom version of Unique to make `Unique::new` const (instead of unsafe). --- Cargo.toml | 1 + src/lib.rs | 1 + src/vga_buffer.rs | 7 +++++++ 3 files changed, 9 insertions(+) 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 8cbf9724..1cd60a46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ #![no_std] extern crate rlibc; +extern crate spin; mod vga_buffer; diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 46c5f73a..d70e1859 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -1,8 +1,15 @@ use core::ptr::Unique; +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 _)}, +}); + #[repr(u8)] pub enum Color { Black = 0, From c547b128e5632cd61824672cc1e6c15d72e37c9d Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 18:04:27 +0200 Subject: [PATCH 4/7] Implement `fmt::Write` trait for Writer --- src/lib.rs | 2 +- src/vga_buffer.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1cd60a46..8be4c8b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ // limitations under the License. #![feature(no_std, lang_items)] -#![feature(const_fn, unique)] +#![feature(const_fn, unique, core_str_ext)] #![no_std] extern crate rlibc; diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index d70e1859..e044d211 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -1,4 +1,5 @@ use core::ptr::Unique; +use core::fmt; use spin::Mutex; const BUFFER_HEIGHT: usize = 25; @@ -78,6 +79,15 @@ impl Writer { } } +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); From e4a8c4c9fa74cc2528c1c8b15a23574ffa4bc4c3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 18:13:05 +0200 Subject: [PATCH 5/7] Silence dead code warnings for unused colors --- src/vga_buffer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index e044d211..75a9b95c 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -11,6 +11,7 @@ pub static WRITER: Mutex = Mutex::new(Writer { buffer: unsafe{Unique::new(0xb8000 as *mut _)}, }); +#[allow(dead_code)] #[repr(u8)] pub enum Color { Black = 0, From 4d29482952850927e2505a4b38b61dd5392206b1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 18:20:26 +0200 Subject: [PATCH 6/7] Add custom `print` and `println` macros --- src/vga_buffer.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 75a9b95c..e16c1647 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -11,6 +11,18 @@ pub static WRITER: Mutex = Mutex::new(Writer { 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 { From 5b1f2361f23a9d479004d8cdf063c708ebacf92a Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 24 Sep 2015 18:20:49 +0200 Subject: [PATCH 7/7] Use `println!` to print the `Hello World! --- src/lib.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8be4c8b4..686f2d24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,23 +19,13 @@ 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{} }