diff --git a/Cargo.lock b/Cargo.lock index 03604ef..43bd876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "mahdi_os" version = "0.1.0" dependencies = [ "rlibc 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -10,3 +11,8 @@ name = "rlibc" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "spin" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/Cargo.toml b/Cargo.toml index d9156bd..7e32671 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ crate-type = ["staticlib"] [dependencies] rlibc = "0.1.4" +spin = "0.3.4" [profile.dev] panic = "abort" diff --git a/Makefile b/Makefile index c8d14ad..ad251ad 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,8 @@ $(iso): $(kernel) $(grub_cfg) @rm -r build/isofiles $(kernel): cargo $(rust_os) $(assembly_object_files) $(linker_script) - @ld -n --gc-sections -T $(linker_script) -o $(kernel) $(assembly_object_files) $(rust_os) + @ld -n --gc-sections -T $(linker_script) -o $(kernel) \ + $(assembly_object_files) $(rust_os) cargo: @cargo build --target $(target) diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d77d7c --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +mahdi-os +======== + +I followed [this tutorial](http://www.randomhacks.net/bare-metal-rust/) to write this, and then tweaked it further and customized it. diff --git a/src/arch/x86_64/boot.asm b/src/arch/x86_64/boot.asm index 2850beb..bea86b9 100644 --- a/src/arch/x86_64/boot.asm +++ b/src/arch/x86_64/boot.asm @@ -13,6 +13,7 @@ start: call set_up_page_tables call enable_paging + call set_up_SSE lgdt [gdt64.pointer] @@ -118,7 +119,7 @@ set_up_page_tables: cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped jne .map_p2_table -ret + ret enable_paging: ; load P4 to cr3 register (cpu uses this to access the P4 table) @@ -169,7 +170,7 @@ section .rodata gdt64: dq 0 ; zero entry .code: equ $ - gdt64 - dq (1 << 44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 54) ; code segment + dq (1 << 44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) ; code segment .data equ $ - gdt64 dq (1 << 44) | (1 << 47) | (1 << 41) ; data segment .pointer: diff --git a/src/arch/x86_64/long_mode_init.asm b/src/arch/x86_64/long_mode_init.asm index 6b23e1a..7678924 100644 --- a/src/arch/x86_64/long_mode_init.asm +++ b/src/arch/x86_64/long_mode_init.asm @@ -7,10 +7,10 @@ long_mode_start: call rust_main ; rust main returned, print `OS returned!` - mov rax, 0x4f724f204f534f4f - mov [0xb8000], rax - mov rax, 0x4f724f754f744f65 - mov [0xb8008], rax - mov rax, 0x4f214f644f654f6e - mov [0xb8010], rax + ; mov rax, 0x4f724f204f534f4f + ; mov [0xb8000], rax + ; mov rax, 0x4f724f754f744f65 + ; mov [0xb8008], rax + ; mov rax, 0x4f214f644f654f6e + ; mov [0xb8010], rax hlt diff --git a/src/lib.rs b/src/lib.rs index 19791bf..b108ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,22 @@ #![feature(lang_items)] #![no_std] +#![feature(unique)] +#![feature(const_fn)] extern crate rlibc; +extern crate spin; + +#[macro_use] +mod vga_buffer; +use 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; - } + use core::fmt::Write; - let buffer_ptr = (0xb8000 + 1988) as *mut _; - unsafe { *buffer_ptr = hello_colored }; + vga_buffer::clear_screen(); + println!("Hello, this is Mahdi OS{}", "!"); loop {} } diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs new file mode 100644 index 0000000..0003f7f --- /dev/null +++ b/src/vga_buffer.rs @@ -0,0 +1,138 @@ +use core::ptr::Unique; +use core::fmt::Write; +use spin::Mutex; + +#[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, +} + +#[derive(Clone, Copy)] +struct ColorCode(u8); + +impl ColorCode { + const fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +struct Buffer { + chars: [[ScreenChar; 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; + + self.buffer().chars[row][col] = ScreenChar { + ascii_character: byte, + color_code: self.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.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: b' ', + color_code: self.color_code, + }; + + self.buffer().chars[row] = [blank; BUFFER_WIDTH]; + } +} + +impl ::core::fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> ::core::fmt::Result { + for byte in s.bytes() { + self.write_byte(byte) + } + Ok(()) + } +} + +pub static WRITER: Mutex = Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::LightCyan, Color::Black), + buffer: unsafe { Unique::new(0xb8000 as *mut _) }, +}); + +macro_rules! print { + ($($arg:tt)*) => ({ + use core::fmt::Write; + let mut writer = $crate::vga_buffer::WRITER.lock(); + writer.write_fmt(format_args!($($arg)*)).unwrap(); + }); +} + +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +pub fn clear_screen() { + for _ in 0..BUFFER_HEIGHT { + println!(""); + } +}