diff --git a/Cargo.toml b/Cargo.toml index 049abb6..649dfd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,10 @@ test = [] qemu_auto_exit = [] link_user_program = [] +[profile.dev] +# enable RVO to avoid stack overflow +opt-level = 1 + [profile.release] debug = true @@ -31,6 +35,7 @@ arrayvec = { version = "0.4.7", default-features = false } log = "0.4" lazy_static = { version = "1.0.0", features = ["spin_no_std"] } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } +bit-allocator = { path = "crate/bit-allocator" } [build-dependencies] cc = "1.0" diff --git a/crate/bit-allocator/src/lib.rs b/crate/bit-allocator/src/lib.rs index 03fa438..016065b 100644 --- a/crate/bit-allocator/src/lib.rs +++ b/crate/bit-allocator/src/lib.rs @@ -10,6 +10,7 @@ pub trait BitAlloc: Default { const CAP: usize; fn alloc(&mut self) -> Option; fn dealloc(&mut self, key: usize); + fn insert(&mut self, range: Range); fn remove(&mut self, range: Range); fn any(&self) -> bool; fn test(&self, key: usize) -> bool; @@ -22,20 +23,12 @@ pub type BitAlloc1M = BitAllocCascade16; pub type BitAlloc16M = BitAllocCascade16; pub type BitAlloc256M = BitAllocCascade16; +#[derive(Default)] pub struct BitAllocCascade16 { bitset: u16, sub: [T; 16], } -impl Default for BitAllocCascade16 { - fn default() -> Self { - Self { - bitset: 0xffff, - sub: <[T; 16]>::default(), - } - } -} - impl BitAlloc for BitAllocCascade16 { const CAP: usize = T::CAP * 16; @@ -54,15 +47,11 @@ impl BitAlloc for BitAllocCascade16 { self.sub[i].dealloc(key % T::CAP); self.bitset.set_bit(i, true); } + fn insert(&mut self, range: Range) { + self.for_range(range, |sub: &mut T, range| sub.insert(range)); + } fn remove(&mut self, range: Range) { - let Range { start, end } = range; - assert!(end <= Self::CAP); - for i in start / T::CAP..=(end - 1) / T::CAP { - let begin = if start / T::CAP == i { start % T::CAP } else { 0 }; - let end = if end / T::CAP == i { end % T::CAP } else { T::CAP }; - self.sub[i].remove(begin..end); - self.bitset.set_bit(i, self.sub[i].any()); - } + self.for_range(range, |sub: &mut T, range| sub.remove(range)); } fn any(&self) -> bool { self.bitset != 0 @@ -72,14 +61,22 @@ impl BitAlloc for BitAllocCascade16 { } } -pub struct BitAlloc16(u16); - -impl Default for BitAlloc16 { - fn default() -> Self { - BitAlloc16(0xffff) +impl BitAllocCascade16 { + fn for_range(&mut self, range: Range, f: impl Fn(&mut T, Range)) { + let Range { start, end } = range; + assert!(end <= Self::CAP); + for i in start / T::CAP..=(end - 1) / T::CAP { + let begin = if start / T::CAP == i { start % T::CAP } else { 0 }; + let end = if end / T::CAP == i { end % T::CAP } else { T::CAP }; + f(&mut self.sub[i], begin..end); + self.bitset.set_bit(i, self.sub[i].any()); + } } } +#[derive(Default)] +pub struct BitAlloc16(u16); + impl BitAlloc for BitAlloc16 { const CAP: usize = 16; @@ -96,6 +93,9 @@ impl BitAlloc for BitAlloc16 { assert!(!self.test(key)); self.0.set_bit(key, true); } + fn insert(&mut self, range: Range) { + self.0.set_bits(range.clone(), 0xffff.get_bits(range)); + } fn remove(&mut self, range: Range) { self.0.set_bits(range, 0); } @@ -141,6 +141,7 @@ mod tests { fn bitalloc16() { let mut ba = BitAlloc16::default(); assert_eq!(BitAlloc16::CAP, 16); + ba.insert(0..16); for i in 0..16 { assert_eq!(ba.test(i), true); } @@ -163,6 +164,7 @@ mod tests { fn bitalloc4k() { let mut ba = BitAlloc4K::default(); assert_eq!(BitAlloc4K::CAP, 4096); + ba.insert(0..4096); for i in 0..4096 { assert_eq!(ba.test(i), true); } diff --git a/src/lib.rs b/src/lib.rs index 37a3ce2..905be4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ extern crate arrayvec; #[macro_use] extern crate log; extern crate simple_filesystem; +extern crate bit_allocator; #[macro_use] // print! mod io; @@ -107,13 +108,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // }); // } - loop{ - println!("init ..."); - let mut i = 0; - while i < 1 << 22 { - i += 1; - } - } + loop {} test_end!(); unreachable!(); diff --git a/src/memory/area_frame_allocator.rs b/src/memory/area_frame_allocator.rs deleted file mode 100644 index 981339b..0000000 --- a/src/memory/area_frame_allocator.rs +++ /dev/null @@ -1,122 +0,0 @@ -use memory::{Frame, FrameAllocator, PhysAddr}; -use multiboot2::{MemoryAreaIter, MemoryArea}; -use arrayvec::ArrayVec; - -pub struct AreaFrameAllocator { - next_free_frame: Frame, - current_area: Option, - areas: ArrayVec<[Area; 4]>, - kernel_start: Frame, - kernel_end: Frame, - multiboot_start: Frame, - multiboot_end: Frame, -} - -// 必须写这句,否则不能放在Mutex中??? -unsafe impl Send for AreaFrameAllocator {} - -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 }; - - // the last frame of the current area - let current_area_last_frame = { - let address = area.end_address() - 1; - Frame::of_addr(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: PhysAddr, kernel_end: PhysAddr, - multiboot_start: PhysAddr, multiboot_end: PhysAddr, - memory_areas: MemoryAreaIter) -> AreaFrameAllocator - { - let areas: ArrayVec<[Area; 4]> = memory_areas.map(|a| Area::from(a)).collect(); - - let mut allocator = AreaFrameAllocator { - next_free_frame: Frame::of_addr(0), - current_area: None, - areas, - kernel_start: Frame::of_addr(kernel_start.0 as usize), - kernel_end: Frame::of_addr(kernel_end.0 as usize), - multiboot_start: Frame::of_addr(multiboot_start.0 as usize), - multiboot_end: Frame::of_addr(multiboot_end.0 as usize), - }; - allocator.choose_next_area(); - allocator - } - - fn choose_next_area(&mut self) { - self.current_area = self.areas.iter().filter(|area| { - let address = area.end_address() - 1; - Frame::of_addr(address as usize) >= self.next_free_frame - }).min_by_key(|area| area.start_address()) - .map(|area| area.clone()); - - if let Some(area) = self.current_area { - let start_frame = Frame::of_addr(area.start_address()); - if self.next_free_frame < start_frame { - self.next_free_frame = start_frame; - } - } - } -} - -#[derive(Debug, Copy, Clone)] -pub struct Area { - start: usize, - end: usize, -} - -impl Area { - pub fn start_address(&self) -> usize { - self.start - } - pub fn end_address(&self) -> usize { - self.end - } - pub fn size(&self) -> usize { - self.end - self.start - } -} - -impl<'a> From<&'a MemoryArea> for Area { - fn from(a: &'a MemoryArea) -> Self { - Area { - start: a.start_address(), - end: a.end_address(), - } - } -} \ No newline at end of file diff --git a/src/memory/mod.rs b/src/memory/mod.rs index cde3d02..70c0026 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,4 +1,3 @@ -pub use self::area_frame_allocator::AreaFrameAllocator; pub use arch::paging::*; pub use self::stack_allocator::*; pub use self::address::*; @@ -12,18 +11,18 @@ use spin::{Mutex, MutexGuard}; use super::HEAP_ALLOCATOR; mod memory_set; -mod area_frame_allocator; pub mod heap_allocator; mod stack_allocator; mod address; mod frame; -pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(None); -pub static STACK_ALLOCATOR: Mutex> = Mutex::new(None); +lazy_static! { + static ref FRAME_ALLOCATOR: Mutex = Mutex::new(BitAlloc64K::default()); +} +static STACK_ALLOCATOR: Mutex> = Mutex::new(None); pub fn alloc_frame() -> Frame { FRAME_ALLOCATOR.lock() - .as_mut().expect("frame allocator is not initialized") .allocate_frame().expect("no more frame") } @@ -69,25 +68,49 @@ pub fn init(boot_info: BootInformation) -> MemorySet { kernel_memory } +use bit_allocator::{BitAlloc64K, BitAlloc}; + +impl FrameAllocator for BitAlloc64K { + fn allocate_frame(&mut self) -> Option { + self.alloc().map(|x| Frame { number: x }) + } + fn deallocate_frame(&mut self, frame: Frame) { + self.dealloc(frame.number); + } +} + fn init_frame_allocator(boot_info: &BootInformation) { - 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 = PhysAddr(elf_sections_tag.sections() - .filter(|s| s.is_allocated()).map(|s| s.start_address()).min().unwrap()); - let kernel_end = PhysAddr::from_kernel_virtual(elf_sections_tag.sections() - .filter(|s| s.is_allocated()).map(|s| s.end_address()).max().unwrap() as usize); - - let boot_info_start = PhysAddr(boot_info.start_address() as u64); - let boot_info_end = PhysAddr(boot_info.end_address() as u64); - - *FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new( - kernel_start, kernel_end, - boot_info_start, boot_info_end, - memory_map_tag.memory_areas(), - )); + let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required") + .memory_areas(); + let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required") + .sections().filter(|s| s.is_allocated()); + + let mut ba = FRAME_ALLOCATOR.lock(); + for area in memory_areas { + ba.insert(to_range(area.start_address(), area.end_address())); + } + for section in elf_sections { + ba.remove(to_range(section.start_address() as usize, section.end_address() as usize)); + } + ba.remove(to_range(boot_info.start_address(), boot_info.end_address())); + + use core::ops::Range; + fn to_range(mut start_addr: usize, mut end_addr: usize) -> Range { + use consts::KERNEL_OFFSET; + if start_addr >= KERNEL_OFFSET { + start_addr -= KERNEL_OFFSET; + } + if end_addr >= KERNEL_OFFSET { + end_addr -= KERNEL_OFFSET; + } + let page_start = start_addr / PAGE_SIZE; + let mut page_end = (end_addr - 1) / PAGE_SIZE + 1; + if page_end >= BitAlloc64K::CAP { + warn!("page num {:#x} out of range {:#x}", page_end, BitAlloc64K::CAP); + page_end = BitAlloc64K::CAP; + } + page_start..page_end + } } fn remap_the_kernel(boot_info: BootInformation) -> MemorySet { @@ -96,7 +119,6 @@ fn remap_the_kernel(boot_info: BootInformation) -> MemorySet { use consts::{KERNEL_OFFSET, KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; memory_set.push(MemoryArea::new_kernel(KERNEL_OFFSET + 0xb8000, KERNEL_OFFSET + 0xb9000, MemoryAttr::default(), "VGA")); memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap")); - debug!("{:#x?}", memory_set); memory_set.switch(); diff --git a/src/process/mod.rs b/src/process/mod.rs index 9b91f41..c615875 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -27,13 +27,7 @@ pub fn init(mut ms: MemorySet) { pub static PROCESSOR: Once> = Once::new(); extern fn idle_thread(arg: usize) -> ! { - loop { - println!("idle ..."); - let mut i = 0; - while i < 1 << 22 { - i += 1; - } - } + loop {} } pub fn add_user_process(name: impl AsRef, data: &[u8]) {