heap allocator in place, no free yet

This commit is contained in:
Jack Halford 2018-03-12 17:48:24 +01:00
parent 36b51236b3
commit 3dfc440d20
10 changed files with 247 additions and 185 deletions

2
kernel-rs/Xargo.toml Normal file
View file

@ -0,0 +1,2 @@
[target.x86-bluesnow.dependencies]
alloc = {}

View file

@ -3,24 +3,28 @@ extern crate core;
use acpi; use acpi;
use cpuio; use cpuio;
use context;
use memory;
use x86; use x86;
use core::char; use core::char;
use vga::*; use vga::*;
fn dispatch(command: &str) -> Result <(), &'static str> { fn dispatch(command: &str) -> Result <(), &'static str> {
match command { match command {
"acpi" => self::acpi_info(),
"help" | "h" => self::help(), "help" | "h" => self::help(),
"memory" => self::mb2_memory(),
"multiboot" => self::mb2_info(), // multiboot
// "memory" => self::mb2_memory(),
// "multiboot" => self::mb2_info(),
// "sections" => self::mb2_sections(),
// ACPI
"acpi" => self::acpi_info(),
"reboot" => self::reboot(), "reboot" => self::reboot(),
"sections" => self::mb2_sections(),
"shutdown" | "halt" | "q" => self::shutdown(), "shutdown" | "halt" | "q" => self::shutdown(),
// others
"stack" => self::print_stack(), "stack" => self::print_stack(),
"test" => self::test(),
"regs" => self::regs(), "regs" => self::regs(),
_ => Err("Command unknown. (h|help for help)"), _ => Err("Command unknown. (h|help for help)"),
} }
} }
@ -48,12 +52,6 @@ fn help() -> Result <(), &'static str> {
Ok(()) Ok(())
} }
fn test() -> Result<(), &'static str>
{
memory::test_paging(context::frame_allocator());
Ok(())
}
/// Reboot the kernel /// Reboot the kernel
/// ///
/// If reboot failed, will loop on a halt cmd /// If reboot failed, will loop on a halt cmd
@ -129,49 +127,49 @@ fn print_stack() -> Result <(), &'static str> {
Ok(()) Ok(())
} }
fn mb2_memory() -> Result <(), &'static str> { // fn mb2_memory() -> Result <(), &'static str> {
let boot_info = context::boot_info(); // let boot_info = context::boot_info();
let memory_map_tag = boot_info.memory_map_tag() // let memory_map_tag = boot_info.memory_map_tag()
.expect("Memory map tag required"); // .expect("Memory map tag required");
println!("memory areas:"); // println!("memory areas:");
for area in memory_map_tag.memory_areas() { // for area in memory_map_tag.memory_areas() {
println!(" start: 0x{:x}, length: 0x{:x}", // println!(" start: 0x{:x}, length: 0x{:x}",
area.start_address(), area.size()); // area.start_address(), area.size());
} // }
Ok(()) // Ok(())
} // }
fn mb2_sections() -> Result <(), &'static str> { // fn mb2_sections() -> Result <(), &'static str> {
let boot_info = context::boot_info(); // let boot_info = context::boot_info();
let elf_sections_tag = boot_info.elf_sections_tag() // let elf_sections_tag = boot_info.elf_sections_tag()
.expect("Elf-sections tag required"); // .expect("Elf-sections tag required");
println!("kernel sections:"); // println!("kernel sections:");
for section in elf_sections_tag.sections() { // for section in elf_sections_tag.sections() {
println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}", // println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}",
section.name(), section.start_address(), section.size(), section.flags()); // section.name(), section.start_address(), section.size(), section.flags());
} // }
Ok(()) // Ok(())
} // }
fn mb2_info() -> Result <(), &'static str> { // fn mb2_info() -> Result <(), &'static str> {
let boot_info = context::boot_info(); // let boot_info = context::boot_info();
let command_line_tag = boot_info.command_line_tag() // let command_line_tag = boot_info.command_line_tag()
.expect("Elf-sections tag required"); // .expect("Elf-sections tag required");
let bootloader_tag = boot_info.boot_loader_name_tag() // let bootloader_tag = boot_info.boot_loader_name_tag()
.expect("Elf-sections tag required"); // .expect("Elf-sections tag required");
println!("bootloader: {}", bootloader_tag.name()); // println!("bootloader: {}", bootloader_tag.name());
if command_line_tag.command_line().len() != 0 { // if command_line_tag.command_line().len() != 0 {
println!("command line: {}", command_line_tag.command_line()); // println!("command line: {}", command_line_tag.command_line());
} // }
Ok(()) // Ok(())
} // }
pub fn acpi_info() -> Result <(), &'static str> { pub fn acpi_info() -> Result <(), &'static str> {
acpi::info()?; acpi::info()?;

View file

@ -6,8 +6,6 @@ pub static mut CONTEXT: Option<Context> = None;
pub struct Context { pub struct Context {
pub current_term: u8, pub current_term: u8,
pub boot_info: multiboot2::BootInformation,
pub frame_allocator: memory::AreaFrameAllocator,
pub vga1: vga::Writer, pub vga1: vga::Writer,
pub vga2: vga::Writer, pub vga2: vga::Writer,
} }
@ -15,94 +13,14 @@ pub struct Context {
impl Context impl Context
{ {
pub fn new(multiboot_start: usize) -> Context { pub fn new(multiboot_start: usize) -> Context {
let boot_info = unsafe { multiboot2::load(multiboot_start) };
let multiboot_end = multiboot_start + boot_info.total_size();
let elf_sections_tag = boot_info.elf_sections_tag().unwrap();
let memory_map_tag = boot_info.memory_map_tag().unwrap();
let kernel_start = elf_sections_tag.sections().map(
|s| s.start_address())
.min().unwrap() as usize;
let kernel_end = elf_sections_tag.sections().map(
|s| s.start_address() + s.size())
.max().unwrap() as usize;
let frame_allocator = memory::AreaFrameAllocator::new(
kernel_start, kernel_end, multiboot_start,
multiboot_end, memory_map_tag.memory_areas());
let vga1 = vga::Writer::new();
let vga2 = vga::Writer::new();
Context { Context {
current_term: 0, current_term: 0,
boot_info, boot_info,
frame_allocator,
vga1, vga1,
vga2, vga2,
} }
} }
} }
pub fn init_screen() {
set_color!(White, Cyan);
print!("{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
format_args!("{: ^80}", r#" ,--, "#),
format_args!("{: ^80}", r#" ,--.'| ,----, "#),
format_args!("{: ^80}", r#" ,--, | : .' .' \ "#),
format_args!("{: ^80}", r#",---.'| : ' ,----,' | "#),
format_args!("{: ^80}", r#"; : | | ; | : . ; "#),
format_args!("{: ^80}", r#"| | : _' | ; |.' / "#),
format_args!("{: ^80}", r#": : |.' | `----'/ ; "#),
format_args!("{: ^80}", r#"| ' ' ; : / ; / "#),
format_args!("{: ^80}", r#"\ \ .'. | ; / /-, "#),
format_args!("{: ^80}", r#" `---`: | ' / / /.`| "#),
format_args!("{: ^80}", r#" ' ; |./__; : "#),
format_args!("{: ^80}", r#" | : ;| : .' "#),
format_args!("{: ^80}", r#" ' ,/ ; | .' "#),
format_args!("{: ^80}", r#" '--' `---' "#));
set_color!();
context().vga1.prompt();
context().vga2.prompt();
context().vga1.flush();
}
pub fn frame_allocator() -> &'static mut memory::AreaFrameAllocator {
&mut context().frame_allocator
}
pub fn boot_info() -> &'static multiboot2::BootInformation {
&context().boot_info
}
pub fn switch_term() {
context().current_term = {
if context().current_term == 0 { 1 }
else { 0 }
};
}
pub fn current_term() -> &'static mut vga::Writer{
if context().current_term == 0 {
&mut context().vga1
} else {
&mut context().vga2
}
}
fn context() -> &'static mut Context {
unsafe {
match CONTEXT {
Some(ref mut x) => &mut *x,
None => panic!(),
}
}
}
pub fn init(multiboot_info_addr: usize) {
unsafe { CONTEXT = Some(Context::new(multiboot_info_addr)) };
memory::remap_the_kernel(frame_allocator(), boot_info());
self::init_screen();
}

View file

@ -1,7 +1,7 @@
extern crate core; extern crate core;
use cpuio; use cpuio;
use context; use vga;
const MAX_KEYS: usize = 59; const MAX_KEYS: usize = 59;
const KEYMAP_US: [[u8;2]; MAX_KEYS] = [ const KEYMAP_US: [[u8;2]; MAX_KEYS] = [
@ -91,19 +91,20 @@ pub fn kbd_callback() {
0x2A | 0x36 => {SHIFT = !is_release}, 0x2A | 0x36 => {SHIFT = !is_release},
0x38 => {ALT = !is_release}, 0x38 => {ALT = !is_release},
0x1D => {CTRL = !is_release}, 0x1D => {CTRL = !is_release},
0x0F if !is_release => { // terminal switching
context::switch_term(); // 0x0F if !is_release => {
context::current_term().flush(); // context::switch_term();
}, // context::current_term().flush();
// },
0x0E if !is_release => { 0x0E if !is_release => {
context::current_term().backspace(); vga::VGA.backspace();
} }
_ => {} _ => {}
} }
}, },
Some(ascii) if !is_release => { Some(ascii) if !is_release => {
let sym = if SHIFT { ascii[1] } else { ascii[0] }; let sym = if SHIFT { ascii[1] } else { ascii[0] };
context::current_term().keypress(sym); vga::VGA.keypress(sym);
}, },
Some(_) => {}, Some(_) => {},
None =>{}, None =>{},

View file

@ -5,15 +5,17 @@
#![feature(const_fn)] #![feature(const_fn)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(asm)] #![feature(asm)]
#![feature(alloc)]
#![feature(allocator_api)]
#![feature(global_allocator)]
extern crate rlibc; extern crate rlibc;
extern crate multiboot2; //slightly modified fork from official 0.3.2 extern crate multiboot2;
#[macro_use] extern crate bitflags; #[macro_use] extern crate bitflags;
#[macro_use] extern crate alloc;
/// 80x25 screen and simplistic terminal driver /// 80x25 screen and simplistic terminal driver
#[macro_use] pub mod vga; #[macro_use] pub mod vga;
/// kernel init and environment
pub mod context;
/// PS/2 detection and processing /// PS/2 detection and processing
pub mod keyboard; pub mod keyboard;
/// simplisitc kernel commands /// simplisitc kernel commands
@ -24,17 +26,37 @@ pub mod cpuio;
pub mod acpi; pub mod acpi;
/// physical frame allocator + paging module /// physical frame allocator + paging module
pub mod memory; pub mod memory;
/// a few x86 instruction wrappers /// a few x86 register and instruction wrappers
pub mod x86; pub mod x86;
#[no_mangle] #[no_mangle]
pub extern fn kmain(multiboot_info_addr: usize) -> ! { pub extern fn kmain(multiboot_info_addr: usize) -> ! {
context::init(multiboot_info_addr);
// println!("init done!");
// acpi::init().unwrap(); // acpi::init().unwrap();
let boot_info = unsafe { multiboot2::load(multiboot_info_addr) };
enable_write_protect_bit();
vga::init();
memory::init(&boot_info);
use alloc::boxed::Box;
let mut heap_test = Box::new(42);
*heap_test -= 15;
let heap_test2 = Box::new("Hello");
println!("{:?} {:?}", heap_test, heap_test2);
let mut vec_test = vec![1,2,3,4,5,6,7];
vec_test[3] = 42;
for i in &vec_test {
print!("{} ", i);
}
loop { keyboard::kbd_callback(); } loop { keyboard::kbd_callback(); }
} }
fn enable_write_protect_bit() {
unsafe { x86::cr0_write(x86::cr0() | (1 << 16)) };
}
#[lang = "eh_personality"] #[no_mangle] #[lang = "eh_personality"] #[no_mangle]
pub extern fn eh_personality() { pub extern fn eh_personality() {
@ -51,3 +73,11 @@ pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32
} }
use memory::BumpAllocator;
pub const HEAP_START: usize = (1 << 22); //first entry of p2
pub const HEAP_SIZE: usize = 100 * 1024; //100 KiB
#[global_allocator]
static HEAP_ALLOCATOR: BumpAllocator = BumpAllocator::new(HEAP_START,
HEAP_START + HEAP_SIZE);

View file

@ -0,0 +1,60 @@
use alloc::heap::{Alloc, AllocErr, Layout};
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub struct BumpAllocator {
heap_start: usize,
heap_end: usize,
next: AtomicUsize,
}
impl BumpAllocator {
pub const fn new(heap_start: usize, heap_end: usize) -> Self {
Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
}
}
unsafe impl<'a> Alloc for &'a BumpAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
loop {
// load current state of the `next` field
let current_next = self.next.load(Ordering::Relaxed);
let alloc_start = align_up(current_next, layout.align());
let alloc_end = alloc_start.saturating_add(layout.size());
if alloc_end <= self.heap_end {
// update the `next` pointer if it still has the value `current_next`
let next_now = self.next.compare_and_swap(current_next, alloc_end,
Ordering::Relaxed);
if next_now == current_next {
return Ok(alloc_start as *mut u8);
}
} else {
return Err(AllocErr::Exhausted{ request: layout })
}
}
}
unsafe fn dealloc(&mut self, pt: *mut u8, layout: Layout) {
// TODO
// do nothing, leak memory
}
}
/// Align downwards. Returns the greatest x with alignment `align`
/// so that x <= addr. The alignment must be a power of 2.
pub fn align_down(addr: usize, align: usize) -> usize {
if align.is_power_of_two() {
addr & !(align - 1)
} else if align == 0 {
addr
} else {
panic!("`align` must be a power of 2");
}
}
/// Align upwards. Returns the smallest x with alignment `align`
/// so that x >= addr. The alignment must be a power of 2.
pub fn align_up(addr: usize, align: usize) -> usize {
align_down(addr + align - 1, align)
}

View file

@ -1,12 +1,14 @@
pub const PAGE_SIZE: usize = 4096; pub const PAGE_SIZE: usize = 4096;
mod area_allocator; mod area_allocator;
mod heap_allocator;
mod paging; mod paging;
pub use self::area_allocator::*; pub use self::area_allocator::*;
pub use self::paging::test_paging; pub use self::heap_allocator::*;
pub use self::paging::remap_the_kernel; pub use self::paging::remap_the_kernel;
use self::paging::PhysicalAddress; use self::paging::PhysicalAddress;
use multiboot2;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Frame { pub struct Frame {
@ -57,3 +59,36 @@ impl Iterator for FrameIter {
} }
} }
} }
/// memory initialisation should only be called once
pub fn init(boot_info: &multiboot2::BootInformation) {
let elf_sections_tag = boot_info.elf_sections_tag().unwrap();
let memory_map_tag = boot_info.memory_map_tag().unwrap();
let kernel_start = elf_sections_tag.sections()
.filter(|s| s.is_allocated())
.map(|s| s.start_address())
.min().unwrap();
let kernel_end = elf_sections_tag.sections()
.filter(|s| s.is_allocated())
.map(|s| s.start_address() + s.size())
.max().unwrap();
let mut frame_allocator = self::AreaFrameAllocator::new(
kernel_start as usize, kernel_end as usize,
boot_info.start_address(), boot_info.start_address(),
memory_map_tag.memory_areas());
let mut active_table = paging::remap_the_kernel(&mut frame_allocator,
boot_info);
use self::paging::Page;
use {HEAP_START, HEAP_SIZE};
let heap_start_page = Page::containing_address(HEAP_START);
let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1);
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
active_table.map(page, paging::EntryFlags::WRITABLE, &mut frame_allocator);
}
}

View file

@ -22,7 +22,7 @@ const ENTRY_COUNT: usize = 1024;
pub type PhysicalAddress = usize; pub type PhysicalAddress = usize;
pub type VirtualAddress = usize; pub type VirtualAddress = usize;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Page { pub struct Page {
number: usize, number: usize,
} }
@ -46,6 +46,33 @@ impl Page {
fn p1_index(&self) -> usize { fn p1_index(&self) -> usize {
(self.number >> 0) & 0x3ff (self.number >> 0) & 0x3ff
} }
pub fn range_inclusive(start: Page, end: Page) -> PageIter {
PageIter {
start,
end,
}
}
}
#[derive(Clone)]
pub struct PageIter {
start: Page,
end: Page,
}
impl Iterator for PageIter {
type Item = Page;
fn next(&mut self) -> Option<Page> {
if self.start <= self.end {
let page = self.start;
self.start.number += 1;
Some(page)
} else {
None
}
}
} }
pub struct ActivePageTable { pub struct ActivePageTable {
@ -99,14 +126,12 @@ impl ActivePageTable {
let p2_frame = Frame::containing_address(x86::cr3() as usize); let p2_frame = Frame::containing_address(x86::cr3() as usize);
println!("old p2_frame at {}", p2_frame.number);
let old_table = InactivePageTable { let old_table = InactivePageTable {
p2_frame, p2_frame,
}; };
unsafe { unsafe {
let frame = Frame::containing_address(new_table.p2_frame.start_address()); let frame = Frame::containing_address(new_table.p2_frame.start_address());
println!("new p2_frame at {:#x}", new_table.p2_frame.start_address());
x86::cr3_write(frame.start_address()); x86::cr3_write(frame.start_address());
} }
@ -166,9 +191,6 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
assert!(section.start_address() % PAGE_SIZE as u64 == 0, assert!(section.start_address() % PAGE_SIZE as u64 == 0,
"sections need to be page aligned"); "sections need to be page aligned");
println!("mapping section at addr: {:#x}, size: {:#x}",
section.start_address(), section.size());
let flags = EntryFlags::from_elf_section_flags(&section); let flags = EntryFlags::from_elf_section_flags(&section);
let start_frame = Frame::containing_address(section.start_address() as usize); let start_frame = Frame::containing_address(section.start_address() as usize);
let end_frame = Frame::containing_address(section.end_address() as usize - 1); let end_frame = Frame::containing_address(section.end_address() as usize - 1);
@ -192,31 +214,5 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
active_table.unmap(old_p2_page, allocator); active_table.unmap(old_p2_page, allocator);
println!("guard page at {:#x}", old_p2_page.start_address());
println!("cr3 = {:#x}", x86::cr3());
active_table active_table
} }
pub fn test_paging<A>(allocator: &mut A)
where A: FrameAllocator
{
let mut page_table = unsafe { ActivePageTable::new() };
let addr = 0xffff_f000;
let page = Page::containing_address(addr);
let frame = allocator.allocate_frame().expect("no more frames");
println!("None = {:?}, map to {:?}",
page_table.translate(addr),
frame);
println!("check 0");
flush!();
page_table.map_to(page, frame, EntryFlags::empty(), allocator);
println!("check 1");
flush!();
println!("Some = {:?}", page_table.translate(addr));
flush!();
println!("next free frame: {:?}", allocator.allocate_frame());
flush!();
}

View file

@ -51,7 +51,6 @@ impl<L> Table<L> where L: HierarchicalLevel
where A: FrameAllocator where A: FrameAllocator
{ {
if self.next_table(index).is_none() { if self.next_table(index).is_none() {
println!("index={} flags={:#b}", index, self[index].flags());
assert!(!self[index].flags().contains(EntryFlags::HUGE_PAGE), assert!(!self[index].flags().contains(EntryFlags::HUGE_PAGE),
"mapping code does not support huge pages"); "mapping code does not support huge pages");
let frame = allocator.allocate_frame().expect("no frames available"); let frame = allocator.allocate_frame().expect("no frames available");

View file

@ -2,10 +2,11 @@ pub mod color;
pub use self::color::{Color, ColorCode}; pub use self::color::{Color, ColorCode};
use context;
use cpuio; use cpuio;
use console; use console;
pub static mut VGA: Writer = self::Writer::new();
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
struct ScreenChar { struct ScreenChar {
@ -25,21 +26,21 @@ macro_rules! println {
} }
macro_rules! flush { macro_rules! flush {
() => ($crate::context::current_term().flush()); () => (unsafe { $crate::vga::VGA.flush() });
} }
macro_rules! set_color { macro_rules! set_color {
() => ($crate::context::current_term().color_code = () => (unsafe { $crate::vga::VGA.color_code =
$crate::vga::ColorCode::new($crate::vga::Color::White, $crate::vga::Color::Black)); $crate::vga::ColorCode::new($crate::vga::Color::White, $crate::vga::Color::Black)} );
($fg:ident) => ($crate::context::current_term().color_code = ($fg:ident) => (unsafe { $crate::vga::VGA.color_code =
$crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::Black)); $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::Black)} );
($fg:ident, $bg:ident) => ($crate::context::current_term().color_code = ($fg:ident, $bg:ident) => (unsafe { $crate::vga::VGA.color_code =
$crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::$bg)); $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::$bg)} );
} }
pub fn print(args: fmt::Arguments) { pub fn print(args: fmt::Arguments) {
use core::fmt::Write; use core::fmt::Write;
context::current_term().write_fmt(args).unwrap(); unsafe { self::VGA.write_fmt(args).unwrap(); }
} }
extern crate core; extern crate core;
@ -195,3 +196,25 @@ impl fmt::Write for Writer {
Ok(()) Ok(())
} }
} }
pub fn init() {
set_color!(White, Cyan);
print!("{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
format_args!("{: ^80}", r#" ,--, "#),
format_args!("{: ^80}", r#" ,--.'| ,----, "#),
format_args!("{: ^80}", r#" ,--, | : .' .' \ "#),
format_args!("{: ^80}", r#",---.'| : ' ,----,' | "#),
format_args!("{: ^80}", r#"; : | | ; | : . ; "#),
format_args!("{: ^80}", r#"| | : _' | ; |.' / "#),
format_args!("{: ^80}", r#": : |.' | `----'/ ; "#),
format_args!("{: ^80}", r#"| ' ' ; : / ; / "#),
format_args!("{: ^80}", r#"\ \ .'. | ; / /-, "#),
format_args!("{: ^80}", r#" `---`: | ' / / /.`| "#),
format_args!("{: ^80}", r#" ' ; |./__; : "#),
format_args!("{: ^80}", r#" | : ;| : .' "#),
format_args!("{: ^80}", r#" ' ,/ ; | .' "#),
format_args!("{: ^80}", r#" '--' `---' "#));
set_color!();
unsafe { VGA.prompt(); }
unsafe { VGA.flush(); }
}