Compare commits

...

12 Commits

Author SHA1 Message Date
Philipp Oppermann
9f1a69cafa Create a new AreaFrameAllocator and allocate maximum number of frames 2017-11-19 10:39:13 +01:00
Philipp Oppermann
edb2e693da Create an AreaFrameAllocator 2017-11-19 10:39:13 +01:00
Philipp Oppermann
84c337e6f0 Create a memory module with a Frame struct and FrameAllocator trait 2017-11-19 10:39:13 +01:00
Philipp Oppermann
98d97703f4 Calculate start and end of kernel and multiboot struct 2017-11-19 10:39:13 +01:00
Philipp Oppermann
402ec77bc0 Reduce number of ELF section by merging .text.* (etc.) sections together 2017-11-19 10:39:13 +01:00
Philipp Oppermann
9a86f60835 Print kernel ELF sections 2017-11-19 10:39:13 +01:00
Philipp Oppermann
cbc9e112bd Print a proper message on panics 2017-11-19 10:39:13 +01:00
Philipp Oppermann
f231f2c7f2 Print available memory areas 2017-11-19 10:39:13 +01:00
Philipp Oppermann
5f65e1d31f Add dependency on multiboot2 crate 2017-11-19 10:39:13 +01:00
Philipp Oppermann
28ce5310c8 Pass address of multiboot info structure to rust_main 2017-11-19 10:39:13 +01:00
Philipp Oppermann
08a4e795a4 Increase stack size to 16k 2017-11-19 10:39:13 +01:00
Philipp Oppermann
8040f8d565 Update Readme for “Allocating Frames” post 2017-11-19 10:39:13 +01:00
7 changed files with 173 additions and 8 deletions

View File

@@ -10,3 +10,4 @@ crate-type = ["staticlib"]
rlibc = "1.0"
volatile = "0.1.0"
spin = "0.4.5"
multiboot2 = "0.1.0"

View File

@@ -1,7 +1,7 @@
# Blog OS (Printing To Screen)
[![Build Status](https://travis-ci.org/phil-opp/blog_os.svg?branch=post_4)](https://travis-ci.org/phil-opp/blog_os/branches)
# Blog OS (Allocating Frames)
[![Build Status](https://travis-ci.org/phil-opp/blog_os.svg?branch=post_5)](https://travis-ci.org/phil-opp/blog_os/branches)
This repository contains the source code for the [Printing To Screen](http://os.phil-opp.com/printing-to-screen.html) post of the [Writing an OS in Rust](http://os.phil-opp.com) series.
This repository contains the source code for the [Allocating Frames](http://os.phil-opp.com/allocating-frames.html) post of the [Writing an OS in Rust](http://os.phil-opp.com) series.
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**

View File

@@ -5,6 +5,7 @@ section .text
bits 32
start:
mov esp, stack_top
mov edi, ebx ; move Multiboot info pointer to edi
call check_multiboot
call check_cpuid
@@ -151,7 +152,7 @@ p3_table:
p2_table:
resb 4096
stack_bottom:
resb 64
resb 4096 * 4
stack_top:
section .rodata

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

View File

@@ -7,19 +7,65 @@
extern crate rlibc;
extern crate volatile;
extern crate spin;
extern crate multiboot2;
#[macro_use]
mod vga_buffer;
mod memory;
#[no_mangle]
pub extern fn rust_main() {
// ATTENTION: we have a very small stack and no guard page
pub extern fn rust_main(multiboot_information_address: usize) {
use memory::FrameAllocator;
vga_buffer::clear_screen();
println!("Hello World{}", "!");
let boot_info = unsafe{ multiboot2::load(multiboot_information_address) };
let memory_map_tag = boot_info.memory_map_tag()
.expect("Memory map tag required");
println!("memory areas:");
for area in memory_map_tag.memory_areas() {
println!(" start: 0x{:x}, length: 0x{:x}",
area.base_addr, area.length);
}
let elf_sections_tag = boot_info.elf_sections_tag()
.expect("Elf-sections tag required");
println!("kernel sections:");
for section in elf_sections_tag.sections() {
println!(" addr: 0x{:x}, size: 0x{:x}, flags: 0x{:x}",
section.addr, section.size, section.flags);
}
let kernel_start = elf_sections_tag.sections().map(|s| s.addr)
.min().unwrap();
let kernel_end = elf_sections_tag.sections().map(|s| s.addr + s.size)
.max().unwrap();
let multiboot_start = multiboot_information_address;
let multiboot_end = multiboot_start + (boot_info.total_size as usize);
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{}
}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! {loop{}}
#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
println!("\n\nPANIC in {} at line {}:", 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 };
// the last frame of the current area
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 {
// 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 // no free frames left
}
}
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;
}
}
}
}

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

@@ -0,0 +1,21 @@
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);
}