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