mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
12 Commits
first_edit
...
first_edit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f1a69cafa | ||
|
|
edb2e693da | ||
|
|
84c337e6f0 | ||
|
|
98d97703f4 | ||
|
|
402ec77bc0 | ||
|
|
9a86f60835 | ||
|
|
cbc9e112bd | ||
|
|
f231f2c7f2 | ||
|
|
5f65e1d31f | ||
|
|
28ce5310c8 | ||
|
|
08a4e795a4 | ||
|
|
8040f8d565 |
@@ -10,3 +10,4 @@ crate-type = ["staticlib"]
|
||||
rlibc = "1.0"
|
||||
volatile = "0.1.0"
|
||||
spin = "0.4.5"
|
||||
multiboot2 = "0.1.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Blog OS (Printing To Screen)
|
||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||
# Blog OS (Allocating Frames)
|
||||
[](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.**
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.*)
|
||||
}
|
||||
}
|
||||
|
||||
52
src/lib.rs
52
src/lib.rs
@@ -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{}
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
// 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
21
src/memory/mod.rs
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user