feat(frames): frame allocator

feat(debug): debug information about multiboot2's memory map
feat(panic): print panics in red
This commit is contained in:
Mahdi Dibaiee 2016-06-25 20:01:45 +04:30
parent 613f2a059e
commit f300229fa4
9 changed files with 202 additions and 4 deletions

14
Cargo.lock generated
View File

@ -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"

View File

@ -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]

View File

@ -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:

View File

@ -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.*)
}
}

32
src/debug.rs Normal file
View File

@ -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)
}

View File

@ -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 {}
}

View File

@ -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<Frame> {
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;
}
}
}
}

20
src/memory/mod.rs Normal file
View File

@ -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<Frame>;
fn deallocate_frame(&mut self, frame: Frame);
}

View File

@ -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() }
}