diff --git a/Cargo.toml b/Cargo.toml index ac97b9b..15b45f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,5 +18,5 @@ once = "0.3.3" linked_list_allocator = "0.5.0" [dependencies.lazy_static] -version = "0.2.4" +version = "1.0.0" features = ["spin_no_std"] diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs new file mode 100644 index 0000000..1cd9f47 --- /dev/null +++ b/src/arch/x86_64/cpu.rs @@ -0,0 +1,21 @@ +// Enable 'No-Execute' bit in page entry +pub fn enable_nxe_bit() { + use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr}; + + let nxe_bit = 1 << 11; + // The EFER register is only allowed in kernel mode + // But we are in kernel mode. So it's safe. + unsafe { + let efer = rdmsr(IA32_EFER); + wrmsr(IA32_EFER, efer | nxe_bit); + } +} + +// Enable write protection in kernel mode +pub fn enable_write_protect_bit() { + use x86_64::registers::control_regs::{cr0, cr0_write, Cr0}; + + // The CR0 register is only allowed in kernel mode + // But we are in kernel mode. So it's safe. + unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) }; +} \ No newline at end of file diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs new file mode 100644 index 0000000..9b00c35 --- /dev/null +++ b/src/arch/x86_64/driver/mod.rs @@ -0,0 +1 @@ +pub mod vga; \ No newline at end of file diff --git a/src/arch/x86_64/driver/vga.rs b/src/arch/x86_64/driver/vga.rs new file mode 100644 index 0000000..a405efe --- /dev/null +++ b/src/arch/x86_64/driver/vga.rs @@ -0,0 +1,90 @@ +use spin::Mutex; +use core::ptr::Unique; +use volatile::Volatile; + +pub const VGA_BUFFER: Unique = unsafe{ + Unique::new_unchecked(0xb8000 as *mut _) +}; + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +#[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, +} + +#[derive(Debug, Clone, Copy)] +struct ColorCode(u8); + +impl ColorCode { + const fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +struct ScreenChar { + ascii_char: u8, + color_code: ColorCode, +} + +pub const BUFFER_HEIGHT: usize = 25; +pub const BUFFER_WIDTH: usize = 80; + +pub struct VgaBuffer { + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +impl VgaBuffer { + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_char: b' ', + color_code: ColorCode::new(Color::White, Color::Black), + }; + for col in 0..BUFFER_WIDTH { + self.chars[row][col].write(blank); + } + } + pub fn clear(&mut self) { + for i in 0 .. BUFFER_HEIGHT { + self.clear_row(i); + } + } + pub fn write(&mut self, row: usize, col: usize, byte: u8) { + let screen_char = &mut self.chars[row][col]; + let color_code = screen_char.read().color_code; + screen_char.write(ScreenChar { + ascii_char: byte, + color_code: color_code, + }); + } + pub fn byte_at(&self, row: usize, col: usize) -> u8 { + self.chars[row][col].read().ascii_char + } +} + +#[cfg(test)] +mod test { + #[test] + fn print_something() { + let vga = unsafe {&mut *VGA_BUFFER}; + vga.clear(); + vga.write(0, 0, b'a'); + } +} \ No newline at end of file diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index cdb5aec..eaf8d38 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -1,26 +1,7 @@ -// Enable 'No-Execute' bit in page entry -fn enable_nxe_bit() { - use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr}; - - let nxe_bit = 1 << 11; - // The EFER register is only allowed in kernel mode - // But we are in kernel mode. So it's safe. - unsafe { - let efer = rdmsr(IA32_EFER); - wrmsr(IA32_EFER, efer | nxe_bit); - } -} - -// Enable write protection in kernel mode -fn enable_write_protect_bit() { - use x86_64::registers::control_regs::{cr0, cr0_write, Cr0}; - - // The CR0 register is only allowed in kernel mode - // But we are in kernel mode. So it's safe. - unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) }; -} +pub mod driver; +mod cpu; pub fn init() { - enable_nxe_bit(); - enable_write_protect_bit(); + cpu::enable_nxe_bit(); + cpu::enable_write_protect_bit(); } \ No newline at end of file diff --git a/src/io/mod.rs b/src/io/mod.rs new file mode 100644 index 0000000..413a637 --- /dev/null +++ b/src/io/mod.rs @@ -0,0 +1,23 @@ +use core::fmt; + +mod vga_writer; + +macro_rules! print { + ($($arg:tt)*) => ({ + $crate::io::print(format_args!($($arg)*)); + }); +} + +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +pub fn print(args: fmt::Arguments) { + use core::fmt::Write; + vga_writer::VGA_WRITER.lock().write_fmt(args).unwrap(); +} + +pub fn init() { + +} \ No newline at end of file diff --git a/src/io/vga_writer.rs b/src/io/vga_writer.rs new file mode 100644 index 0000000..482483d --- /dev/null +++ b/src/io/vga_writer.rs @@ -0,0 +1,66 @@ +use spin::Mutex; +use core::fmt; +use arch::driver::vga::*; + +lazy_static! { + pub static ref VGA_WRITER: Mutex = Mutex::new( + // It is the only user of VGA_BUFFER. So it's safe. + VgaWriter::new(unsafe{ &mut *VGA_BUFFER.as_ptr() }) + ); +} + +pub struct VgaWriter { + column_position: usize, + color: Color, + buffer: &'static mut VgaBuffer +} + +impl VgaWriter { + fn new(buffer: &'static mut VgaBuffer) -> Self { + buffer.clear(); + VgaWriter { + column_position: 0, + color: Color::White, + buffer: buffer, + } + } + + 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.write(row, col, byte); + self.column_position += 1; + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + let byte = self.buffer.byte_at(row, col); + self.buffer.write(row-1, col, byte); + } + } + for col in 0..BUFFER_WIDTH { + self.buffer.write(BUFFER_HEIGHT-1, col, b' '); + } + self.column_position = 0; + } +} + +impl fmt::Write for VgaWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + self.write_byte(byte) + } + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 4b93db9..35e44c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,8 +27,8 @@ extern crate linked_list_allocator; extern crate lazy_static; extern crate bit_field; -#[macro_use] // println! -mod vga_buffer; +#[macro_use] // print! +mod io; mod memory; mod interrupts; mod lang; @@ -42,7 +42,7 @@ mod arch; #[no_mangle] pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page - vga_buffer::clear_screen(); + io::init(); println!("Hello World{}", "!"); let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs deleted file mode 100644 index f36b9cd..0000000 --- a/src/vga_buffer.rs +++ /dev/null @@ -1,147 +0,0 @@ -use core::fmt; -use core::ptr::Unique; -use spin::Mutex; -use volatile::Volatile; - -pub static WRITER: Mutex = Mutex::new(Writer { - column_position: 0, - color_code: ColorCode::new(Color::LightGreen, Color::Black), - buffer: unsafe { Unique::new_unchecked(0xb8000 as *mut _) }, -}); - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -#[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, -} - -#[derive(Debug, Clone, Copy)] -struct ColorCode(u8); - -impl ColorCode { - const fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 4 | (foreground as u8)) - } -} - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -struct ScreenChar { - ascii_character: u8, - color_code: ColorCode, -} - -const BUFFER_HEIGHT: usize = 25; -const BUFFER_WIDTH: usize = 80; - -struct Buffer { - chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], -} - -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; - - 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_str(&mut self, s: &str) { - for byte in s.bytes() { - self.write_byte(byte) - } - } - - fn buffer(&mut self) -> &mut Buffer { - unsafe{ self.buffer.as_mut() } - } - - fn new_line(&mut self) { - for row in 1..BUFFER_HEIGHT { - for col in 0..BUFFER_WIDTH { - let buffer = 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 { - self.buffer().chars[row][col].write(blank); - } - } -} - -impl fmt::Write for Writer { - fn write_str(&mut self, s: &str) -> fmt::Result { - for byte in s.bytes() { - self.write_byte(byte) - } - Ok(()) - } -} - -macro_rules! print { - ($($arg:tt)*) => ({ - $crate::vga_buffer::print(format_args!($($arg)*)); - }); -} - -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -pub fn print(args: fmt::Arguments) { - use core::fmt::Write; - WRITER.lock().write_fmt(args).unwrap(); -} - -pub fn clear_screen() { - for _ in 0..BUFFER_HEIGHT { - println!(""); - } -}