From f300229fa4fe0936781484b54bc80833fad829ea Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Sat, 25 Jun 2016 20:01:45 +0430 Subject: [PATCH] feat(frames): frame allocator feat(debug): debug information about multiboot2's memory map feat(panic): print panics in red --- Cargo.lock | 14 +++++ Cargo.toml | 3 + src/arch/x86_64/boot.asm | 3 +- src/arch/x86_64/linker.ld | 10 +++- src/debug.rs | 32 +++++++++++ src/lib.rs | 32 ++++++++++- src/memory/area_frame_allocator.rs | 88 ++++++++++++++++++++++++++++++ src/memory/mod.rs | 20 +++++++ src/vga_buffer.rs | 4 ++ 9 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 src/debug.rs create mode 100644 src/memory/area_frame_allocator.rs create mode 100644 src/memory/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 43bd876..4cc49f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,24 @@ name = "mahdi_os" version = "0.1.0" dependencies = [ + "multiboot2 0.1.0 (git+https://github.com/phil-opp/multiboot2-elf64)", "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]] +name = "bitflags" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "multiboot2" +version = "0.1.0" +source = "git+https://github.com/phil-opp/multiboot2-elf64#44b4b3f518b35b8e8876783d9d0f9b2760fe6a2e" +dependencies = [ + "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rlibc" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 7e32671..53493bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ crate-type = ["staticlib"] rlibc = "0.1.4" spin = "0.3.4" +[dependencies.multiboot2] +git = "https://github.com/phil-opp/multiboot2-elf64" + [profile.dev] panic = "abort" [profile.release] diff --git a/src/arch/x86_64/boot.asm b/src/arch/x86_64/boot.asm index bea86b9..38163f7 100644 --- a/src/arch/x86_64/boot.asm +++ b/src/arch/x86_64/boot.asm @@ -6,6 +6,7 @@ bits 32 start: ; move stack pointer register mov esp, stack_top + mov edi, ebx call check_multiboot call check_cpuid @@ -186,5 +187,5 @@ p3_table: p2_table: resb 4096 stack_bottom: - resb 64 + resb 4096 stack_top: diff --git a/src/arch/x86_64/linker.ld b/src/arch/x86_64/linker.ld index 9beaca2..16b4e0d 100644 --- a/src/arch/x86_64/linker.ld +++ b/src/arch/x86_64/linker.ld @@ -11,6 +11,14 @@ SECTIONS { .text : { - *(.text) + *(.text .text.*) + } + + .rodata : { + *(.rodata .rodata.*) + } + + .data.rel.ro : { + *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) } } diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..2a842db --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,32 @@ +extern crate multiboot2; +use multiboot2::{ MemoryMapTag }; + +pub fn info(information_address: usize, log: bool) -> (u64, u64, usize, usize, &'static MemoryMapTag) { + let boot_info = unsafe { multiboot2::load(information_address) }; + let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required"); + + let elf_sections_tag = boot_info.elf_sections_tag().expect("Elf-sections tag required"); + + let kernel_start = elf_sections_tag.sections().map(|s| s.addr).min().unwrap(); + let kernel_end = elf_sections_tag.sections().map(|s| s.addr).max().unwrap(); + + let multiboot_start = information_address; + let multiboot_end = information_address + (boot_info.total_size as usize); + + if log { + println!("Memory:"); + for area in memory_map_tag.memory_areas() { + println!("start: 0x{:x}, length: 0x{:x}", area.base_addr, area.length); + } + + println!("Kernel sections:"); + for section in elf_sections_tag.sections() { + println!("start: 0x{:x}, size: 0x{:x}, flags: 0x{:x}", section.addr, section.size, section.flags); + } + + println!("Kernel: start 0x{:x} emd 0x{:x}", kernel_start, kernel_end); + println!("Multiboot: start 0x{:x} emd 0x{:x}", multiboot_start, multiboot_end); + } + + (kernel_start, kernel_end, multiboot_start, multiboot_end, memory_map_tag) +} diff --git a/src/lib.rs b/src/lib.rs index b108ffd..3ae5167 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,19 +5,39 @@ extern crate rlibc; extern crate spin; +extern crate multiboot2; #[macro_use] mod vga_buffer; use vga_buffer::*; +mod debug; +use debug::info; + +mod memory; +use memory::*; + #[no_mangle] -pub extern fn rust_main() { +pub extern fn rust_main(information_address: usize) { // ATTENTION: we have a very small stack and no guard page use core::fmt::Write; vga_buffer::clear_screen(); println!("Hello, this is Mahdi OS{}", "!"); + // show information about memory and kernel sections + let (kernel_start, kernel_end, multiboot_start, multiboot_end, memory_map_tag) = info(information_address, false); + let mut frame_allocator = memory::AreaFrameAllocator::new( + kernel_start as usize, kernel_end as usize, multiboot_start, multiboot_end, + memory_map_tag.memory_areas()); + + for i in 0.. { + if let None = frame_allocator.allocate_frame() { + println!("allocated {} frames", i); + break; + } + } + loop {} } @@ -28,4 +48,12 @@ pub extern "C" fn _Unwind_Resume() -> ! { } #[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} } +#[lang = "panic_fmt"] +extern fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! { + vga_buffer::WRITER.lock().set_color(Color::LightRed, Color::Black); + + println!(""); + println!("DAMN, PANIC in {}:{}", file, line); + println!(" {}", fmt); + loop {} +} diff --git a/src/memory/area_frame_allocator.rs b/src/memory/area_frame_allocator.rs new file mode 100644 index 0000000..13cb4fd --- /dev/null +++ b/src/memory/area_frame_allocator.rs @@ -0,0 +1,88 @@ +use memory::{Frame, FrameAllocator}; +use multiboot2::{MemoryAreaIter, MemoryArea}; + +pub struct AreaFrameAllocator { + next_free_frame: Frame, + current_area: Option<&'static MemoryArea>, + areas: MemoryAreaIter, + kernel_start: Frame, + kernel_end: Frame, + multiboot_start: Frame, + multiboot_end: Frame, +} + +impl FrameAllocator for AreaFrameAllocator { + fn allocate_frame(&mut self) -> Option { + if let Some(area) = self.current_area { + // Clone the frame to return it if it's free. Frame doesn't + // implement Clone, but we can construct an identical frame. + let frame = Frame { number: self.next_free_frame.number }; + + let current_area_last_frame = { + let address = area.base_addr + area.length - 1; + Frame::containing_address(address as usize) + }; + + if frame > current_area_last_frame { + // if all frames of current area are used, switch to next area + self.choose_next_area(); + } else if frame >= self.kernel_start && frame <= self.kernel_end { + // `frame` is used by the kernel + self.next_free_frame = Frame { + number: self.kernel_end.number + 1 + } + } else if frame >= self.multiboot_start && frame <= self.multiboot_end { + // `frame` is used by the multiboot information structure + self.next_free_frame = Frame { + number: self.multiboot_end.number + 1 + }; + } else { + // `frame` is unused, increment `next_free_frame` and return it + self.next_free_frame.number += 1; + return Some(frame); + } + + // `frame` was not valid, try it again with the updated `next_free_frame` + self.allocate_frame() + } else { + None + } + } + + fn deallocate_frame(&mut self, frame: Frame) { + unimplemented!() + } +} + +impl AreaFrameAllocator { + pub fn new(kernel_start: usize, kernel_end: usize, + multiboot_start: usize, multiboot_end: usize, + memory_areas: MemoryAreaIter) -> AreaFrameAllocator { + + let mut allocator = AreaFrameAllocator { + next_free_frame: Frame::containing_address(0), + current_area: None, + areas: memory_areas, + kernel_start: Frame::containing_address(kernel_start), + kernel_end: Frame::containing_address(kernel_end), + multiboot_start: Frame::containing_address(multiboot_start), + multiboot_end: Frame::containing_address(multiboot_end), + }; + + allocator.choose_next_area(); + allocator + } + fn choose_next_area(&mut self) { + self.current_area = self.areas.clone().filter(|area| { + let address = area.base_addr + area.length - 1; + Frame::containing_address(address as usize) >= self.next_free_frame + }).min_by_key(|area| area.base_addr); + + if let Some(area) = self.current_area { + let start_frame = Frame::containing_address(area.base_addr as usize); + if self.next_free_frame < start_frame { + self.next_free_frame = start_frame; + } + } + } +} diff --git a/src/memory/mod.rs b/src/memory/mod.rs new file mode 100644 index 0000000..75e3a6a --- /dev/null +++ b/src/memory/mod.rs @@ -0,0 +1,20 @@ +pub use self::area_frame_allocator::AreaFrameAllocator; +mod area_frame_allocator; + +pub const PAGE_SIZE: usize = 4096; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Frame { + number: usize, +} + +impl Frame { + fn containing_address(address: usize) -> Frame { + Frame { number: address / PAGE_SIZE } + } +} + +pub trait FrameAllocator { + fn allocate_frame(&mut self) -> Option; + fn deallocate_frame(&mut self, frame: Frame); +} diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 0003f7f..83fbb4c 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -79,6 +79,10 @@ impl Writer { } } + pub fn set_color(&mut self, foreground: Color, background: Color) { + self.color_code = ColorCode::new(foreground, background); + } + fn buffer(&mut self) -> &mut Buffer { unsafe { self.buffer.get_mut() } }