feat(frames): frame allocator
feat(debug): debug information about multiboot2's memory map feat(panic): print panics in red
This commit is contained in:
parent
613f2a059e
commit
f300229fa4
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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:
|
||||
|
@ -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
32
src/debug.rs
Normal 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)
|
||||
}
|
32
src/lib.rs
32
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 {}
|
||||
}
|
||||
|
88
src/memory/area_frame_allocator.rs
Normal file
88
src/memory/area_frame_allocator.rs
Normal 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
20
src/memory/mod.rs
Normal 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);
|
||||
}
|
@ -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() }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user