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"
|
name = "mahdi_os"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "rlibc"
|
name = "rlibc"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -10,6 +10,9 @@ crate-type = ["staticlib"]
|
|||||||
rlibc = "0.1.4"
|
rlibc = "0.1.4"
|
||||||
spin = "0.3.4"
|
spin = "0.3.4"
|
||||||
|
|
||||||
|
[dependencies.multiboot2]
|
||||||
|
git = "https://github.com/phil-opp/multiboot2-elf64"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
@ -6,6 +6,7 @@ bits 32
|
|||||||
start:
|
start:
|
||||||
; move stack pointer register
|
; move stack pointer register
|
||||||
mov esp, stack_top
|
mov esp, stack_top
|
||||||
|
mov edi, ebx
|
||||||
|
|
||||||
call check_multiboot
|
call check_multiboot
|
||||||
call check_cpuid
|
call check_cpuid
|
||||||
@ -186,5 +187,5 @@ p3_table:
|
|||||||
p2_table:
|
p2_table:
|
||||||
resb 4096
|
resb 4096
|
||||||
stack_bottom:
|
stack_bottom:
|
||||||
resb 64
|
resb 4096
|
||||||
stack_top:
|
stack_top:
|
||||||
|
@ -11,6 +11,14 @@ SECTIONS {
|
|||||||
|
|
||||||
.text :
|
.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 rlibc;
|
||||||
extern crate spin;
|
extern crate spin;
|
||||||
|
extern crate multiboot2;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod vga_buffer;
|
mod vga_buffer;
|
||||||
use vga_buffer::*;
|
use vga_buffer::*;
|
||||||
|
|
||||||
|
mod debug;
|
||||||
|
use debug::info;
|
||||||
|
|
||||||
|
mod memory;
|
||||||
|
use memory::*;
|
||||||
|
|
||||||
#[no_mangle]
|
#[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
|
// ATTENTION: we have a very small stack and no guard page
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
vga_buffer::clear_screen();
|
vga_buffer::clear_screen();
|
||||||
println!("Hello, this is Mahdi OS{}", "!");
|
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 {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,4 +48,12 @@ pub extern "C" fn _Unwind_Resume() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
#[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 {
|
fn buffer(&mut self) -> &mut Buffer {
|
||||||
unsafe { self.buffer.get_mut() }
|
unsafe { self.buffer.get_mut() }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user