diff --git a/kernel-rs/Xargo.toml b/kernel-rs/Xargo.toml new file mode 100644 index 00000000..91b4c5ff --- /dev/null +++ b/kernel-rs/Xargo.toml @@ -0,0 +1,2 @@ +[target.x86-bluesnow.dependencies] +alloc = {} diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index ea547791..91f046dd 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -3,24 +3,28 @@ extern crate core; use acpi; use cpuio; -use context; -use memory; use x86; use core::char; use vga::*; fn dispatch(command: &str) -> Result <(), &'static str> { match command { - "acpi" => self::acpi_info(), "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(), - "sections" => self::mb2_sections(), "shutdown" | "halt" | "q" => self::shutdown(), + + // others "stack" => self::print_stack(), - "test" => self::test(), "regs" => self::regs(), + _ => Err("Command unknown. (h|help for help)"), } } @@ -48,12 +52,6 @@ fn help() -> Result <(), &'static str> { Ok(()) } -fn test() -> Result<(), &'static str> -{ - memory::test_paging(context::frame_allocator()); - Ok(()) -} - /// Reboot the kernel /// /// If reboot failed, will loop on a halt cmd @@ -129,49 +127,49 @@ fn print_stack() -> Result <(), &'static str> { Ok(()) } -fn mb2_memory() -> Result <(), &'static str> { - let boot_info = context::boot_info(); +// fn mb2_memory() -> Result <(), &'static str> { +// let boot_info = context::boot_info(); - let memory_map_tag = boot_info.memory_map_tag() - .expect("Memory map tag required"); +// 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.start_address(), area.size()); - } - Ok(()) -} +// println!("memory areas:"); +// for area in memory_map_tag.memory_areas() { +// println!(" start: 0x{:x}, length: 0x{:x}", +// area.start_address(), area.size()); +// } +// Ok(()) +// } -fn mb2_sections() -> Result <(), &'static str> { - let boot_info = context::boot_info(); +// fn mb2_sections() -> Result <(), &'static str> { +// let boot_info = context::boot_info(); - let elf_sections_tag = boot_info.elf_sections_tag() - .expect("Elf-sections tag required"); +// 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!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}", - section.name(), section.start_address(), section.size(), section.flags()); - } - Ok(()) -} +// println!("kernel sections:"); +// for section in elf_sections_tag.sections() { +// println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}", +// section.name(), section.start_address(), section.size(), section.flags()); +// } +// Ok(()) +// } -fn mb2_info() -> Result <(), &'static str> { - let boot_info = context::boot_info(); +// fn mb2_info() -> Result <(), &'static str> { +// let boot_info = context::boot_info(); - let command_line_tag = boot_info.command_line_tag() - .expect("Elf-sections tag required"); +// let command_line_tag = boot_info.command_line_tag() +// .expect("Elf-sections tag required"); - let bootloader_tag = boot_info.boot_loader_name_tag() - .expect("Elf-sections tag required"); +// let bootloader_tag = boot_info.boot_loader_name_tag() +// .expect("Elf-sections tag required"); - println!("bootloader: {}", bootloader_tag.name()); - if command_line_tag.command_line().len() != 0 { - println!("command line: {}", command_line_tag.command_line()); - } - Ok(()) -} +// println!("bootloader: {}", bootloader_tag.name()); +// if command_line_tag.command_line().len() != 0 { +// println!("command line: {}", command_line_tag.command_line()); +// } +// Ok(()) +// } pub fn acpi_info() -> Result <(), &'static str> { acpi::info()?; diff --git a/kernel-rs/src/context.rs b/kernel-rs/src/context.rs index 0ac48644..81b76627 100644 --- a/kernel-rs/src/context.rs +++ b/kernel-rs/src/context.rs @@ -6,8 +6,6 @@ pub static mut CONTEXT: Option = None; pub struct Context { pub current_term: u8, - pub boot_info: multiboot2::BootInformation, - pub frame_allocator: memory::AreaFrameAllocator, pub vga1: vga::Writer, pub vga2: vga::Writer, } @@ -15,94 +13,14 @@ pub struct Context { impl 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 { current_term: 0, boot_info, - frame_allocator, vga1, 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(); -} diff --git a/kernel-rs/src/keyboard.rs b/kernel-rs/src/keyboard.rs index 572f7ac4..c29217a8 100644 --- a/kernel-rs/src/keyboard.rs +++ b/kernel-rs/src/keyboard.rs @@ -1,7 +1,7 @@ extern crate core; use cpuio; -use context; +use vga; const MAX_KEYS: usize = 59; const KEYMAP_US: [[u8;2]; MAX_KEYS] = [ @@ -91,19 +91,20 @@ pub fn kbd_callback() { 0x2A | 0x36 => {SHIFT = !is_release}, 0x38 => {ALT = !is_release}, 0x1D => {CTRL = !is_release}, - 0x0F if !is_release => { - context::switch_term(); - context::current_term().flush(); - }, + // terminal switching + // 0x0F if !is_release => { + // context::switch_term(); + // context::current_term().flush(); + // }, 0x0E if !is_release => { - context::current_term().backspace(); + vga::VGA.backspace(); } _ => {} } }, Some(ascii) if !is_release => { let sym = if SHIFT { ascii[1] } else { ascii[0] }; - context::current_term().keypress(sym); + vga::VGA.keypress(sym); }, Some(_) => {}, None =>{}, diff --git a/kernel-rs/src/lib.rs b/kernel-rs/src/lib.rs index 6ea1a015..2a791bc2 100644 --- a/kernel-rs/src/lib.rs +++ b/kernel-rs/src/lib.rs @@ -5,15 +5,17 @@ #![feature(const_fn)] #![feature(ptr_internals)] #![feature(asm)] +#![feature(alloc)] +#![feature(allocator_api)] +#![feature(global_allocator)] 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 alloc; /// 80x25 screen and simplistic terminal driver #[macro_use] pub mod vga; -/// kernel init and environment -pub mod context; /// PS/2 detection and processing pub mod keyboard; /// simplisitc kernel commands @@ -24,17 +26,37 @@ pub mod cpuio; pub mod acpi; /// physical frame allocator + paging module pub mod memory; -/// a few x86 instruction wrappers +/// a few x86 register and instruction wrappers pub mod x86; #[no_mangle] pub extern fn kmain(multiboot_info_addr: usize) -> ! { - context::init(multiboot_info_addr); - // println!("init done!"); // 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(); } } +fn enable_write_protect_bit() { + unsafe { x86::cr0_write(x86::cr0() | (1 << 16)) }; +} + #[lang = "eh_personality"] #[no_mangle] 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); diff --git a/kernel-rs/src/memory/heap_allocator.rs b/kernel-rs/src/memory/heap_allocator.rs new file mode 100644 index 00000000..d6ed05b6 --- /dev/null +++ b/kernel-rs/src/memory/heap_allocator.rs @@ -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) +} diff --git a/kernel-rs/src/memory/mod.rs b/kernel-rs/src/memory/mod.rs index 51629c66..76189437 100644 --- a/kernel-rs/src/memory/mod.rs +++ b/kernel-rs/src/memory/mod.rs @@ -1,12 +1,14 @@ pub const PAGE_SIZE: usize = 4096; mod area_allocator; +mod heap_allocator; mod paging; pub use self::area_allocator::*; -pub use self::paging::test_paging; +pub use self::heap_allocator::*; pub use self::paging::remap_the_kernel; use self::paging::PhysicalAddress; +use multiboot2; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] 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); + } +} diff --git a/kernel-rs/src/memory/paging/mod.rs b/kernel-rs/src/memory/paging/mod.rs index 45a43f81..0e47014a 100644 --- a/kernel-rs/src/memory/paging/mod.rs +++ b/kernel-rs/src/memory/paging/mod.rs @@ -22,7 +22,7 @@ const ENTRY_COUNT: usize = 1024; pub type PhysicalAddress = usize; pub type VirtualAddress = usize; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Page { number: usize, } @@ -46,6 +46,33 @@ impl Page { fn p1_index(&self) -> usize { (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 { + if self.start <= self.end { + let page = self.start; + self.start.number += 1; + Some(page) + } else { + None + } + } } pub struct ActivePageTable { @@ -99,14 +126,12 @@ impl ActivePageTable { let p2_frame = Frame::containing_address(x86::cr3() as usize); - println!("old p2_frame at {}", p2_frame.number); let old_table = InactivePageTable { p2_frame, }; unsafe { 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()); } @@ -166,9 +191,6 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) assert!(section.start_address() % PAGE_SIZE as u64 == 0, "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(§ion); let start_frame = Frame::containing_address(section.start_address() as usize); let end_frame = Frame::containing_address(section.end_address() as usize - 1); @@ -192,31 +214,5 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) active_table.unmap(old_p2_page, allocator); - println!("guard page at {:#x}", old_p2_page.start_address()); - println!("cr3 = {:#x}", x86::cr3()); - active_table } - -pub fn test_paging(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!(); - -} diff --git a/kernel-rs/src/memory/paging/table.rs b/kernel-rs/src/memory/paging/table.rs index 2a9e9a86..da35e011 100644 --- a/kernel-rs/src/memory/paging/table.rs +++ b/kernel-rs/src/memory/paging/table.rs @@ -51,7 +51,6 @@ impl Table where L: HierarchicalLevel where A: FrameAllocator { if self.next_table(index).is_none() { - println!("index={} flags={:#b}", index, self[index].flags()); assert!(!self[index].flags().contains(EntryFlags::HUGE_PAGE), "mapping code does not support huge pages"); let frame = allocator.allocate_frame().expect("no frames available"); diff --git a/kernel-rs/src/vga/mod.rs b/kernel-rs/src/vga/mod.rs index 0a09fe1b..b773b4ff 100644 --- a/kernel-rs/src/vga/mod.rs +++ b/kernel-rs/src/vga/mod.rs @@ -2,10 +2,11 @@ pub mod color; pub use self::color::{Color, ColorCode}; -use context; use cpuio; use console; +pub static mut VGA: Writer = self::Writer::new(); + #[derive(Debug, Clone, Copy)] #[repr(C)] struct ScreenChar { @@ -25,21 +26,21 @@ macro_rules! println { } macro_rules! flush { - () => ($crate::context::current_term().flush()); + () => (unsafe { $crate::vga::VGA.flush() }); } macro_rules! set_color { - () => ($crate::context::current_term().color_code = - $crate::vga::ColorCode::new($crate::vga::Color::White, $crate::vga::Color::Black)); - ($fg:ident) => ($crate::context::current_term().color_code = - $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::Black)); - ($fg:ident, $bg:ident) => ($crate::context::current_term().color_code = - $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::$bg)); + () => (unsafe { $crate::vga::VGA.color_code = + $crate::vga::ColorCode::new($crate::vga::Color::White, $crate::vga::Color::Black)} ); + ($fg:ident) => (unsafe { $crate::vga::VGA.color_code = + $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::Black)} ); + ($fg:ident, $bg:ident) => (unsafe { $crate::vga::VGA.color_code = + $crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::$bg)} ); } pub fn print(args: fmt::Arguments) { use core::fmt::Write; - context::current_term().write_fmt(args).unwrap(); + unsafe { self::VGA.write_fmt(args).unwrap(); } } extern crate core; @@ -195,3 +196,25 @@ impl fmt::Write for Writer { 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(); } +}