Replace `AreaFrameAllocator` by `BitAllocator`. Set opt-level=1 to avoid stack overflow.

master
WangRunji 7 years ago
parent 2762fded9c
commit f3d62a5b8f

@ -12,6 +12,10 @@ test = []
qemu_auto_exit = [] qemu_auto_exit = []
link_user_program = [] link_user_program = []
[profile.dev]
# enable RVO to avoid stack overflow
opt-level = 1
[profile.release] [profile.release]
debug = true debug = true
@ -31,6 +35,7 @@ arrayvec = { version = "0.4.7", default-features = false }
log = "0.4" log = "0.4"
lazy_static = { version = "1.0.0", features = ["spin_no_std"] } lazy_static = { version = "1.0.0", features = ["spin_no_std"] }
simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" }
bit-allocator = { path = "crate/bit-allocator" }
[build-dependencies] [build-dependencies]
cc = "1.0" cc = "1.0"

@ -10,6 +10,7 @@ pub trait BitAlloc: Default {
const CAP: usize; const CAP: usize;
fn alloc(&mut self) -> Option<usize>; fn alloc(&mut self) -> Option<usize>;
fn dealloc(&mut self, key: usize); fn dealloc(&mut self, key: usize);
fn insert(&mut self, range: Range<usize>);
fn remove(&mut self, range: Range<usize>); fn remove(&mut self, range: Range<usize>);
fn any(&self) -> bool; fn any(&self) -> bool;
fn test(&self, key: usize) -> bool; fn test(&self, key: usize) -> bool;
@ -22,20 +23,12 @@ pub type BitAlloc1M = BitAllocCascade16<BitAlloc64K>;
pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>; pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>;
pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>; pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
#[derive(Default)]
pub struct BitAllocCascade16<T: BitAlloc> { pub struct BitAllocCascade16<T: BitAlloc> {
bitset: u16, bitset: u16,
sub: [T; 16], sub: [T; 16],
} }
impl<T: BitAlloc> Default for BitAllocCascade16<T> {
fn default() -> Self {
Self {
bitset: 0xffff,
sub: <[T; 16]>::default(),
}
}
}
impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> { impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
const CAP: usize = T::CAP * 16; const CAP: usize = T::CAP * 16;
@ -54,15 +47,11 @@ impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
self.sub[i].dealloc(key % T::CAP); self.sub[i].dealloc(key % T::CAP);
self.bitset.set_bit(i, true); self.bitset.set_bit(i, true);
} }
fn remove(&mut self, range: Range<usize>) { fn insert(&mut self, range: Range<usize>) {
let Range { start, end } = range; self.for_range(range, |sub: &mut T, range| sub.insert(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());
} }
fn remove(&mut self, range: Range<usize>) {
self.for_range(range, |sub: &mut T, range| sub.remove(range));
} }
fn any(&self) -> bool { fn any(&self) -> bool {
self.bitset != 0 self.bitset != 0
@ -72,14 +61,22 @@ impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
} }
} }
pub struct BitAlloc16(u16); impl<T: BitAlloc> BitAllocCascade16<T> {
fn for_range(&mut self, range: Range<usize>, f: impl Fn(&mut T, Range<usize>)) {
impl Default for BitAlloc16 { let Range { start, end } = range;
fn default() -> Self { assert!(end <= Self::CAP);
BitAlloc16(0xffff) 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 { impl BitAlloc for BitAlloc16 {
const CAP: usize = 16; const CAP: usize = 16;
@ -96,6 +93,9 @@ impl BitAlloc for BitAlloc16 {
assert!(!self.test(key)); assert!(!self.test(key));
self.0.set_bit(key, true); self.0.set_bit(key, true);
} }
fn insert(&mut self, range: Range<usize>) {
self.0.set_bits(range.clone(), 0xffff.get_bits(range));
}
fn remove(&mut self, range: Range<usize>) { fn remove(&mut self, range: Range<usize>) {
self.0.set_bits(range, 0); self.0.set_bits(range, 0);
} }
@ -141,6 +141,7 @@ mod tests {
fn bitalloc16() { fn bitalloc16() {
let mut ba = BitAlloc16::default(); let mut ba = BitAlloc16::default();
assert_eq!(BitAlloc16::CAP, 16); assert_eq!(BitAlloc16::CAP, 16);
ba.insert(0..16);
for i in 0..16 { for i in 0..16 {
assert_eq!(ba.test(i), true); assert_eq!(ba.test(i), true);
} }
@ -163,6 +164,7 @@ mod tests {
fn bitalloc4k() { fn bitalloc4k() {
let mut ba = BitAlloc4K::default(); let mut ba = BitAlloc4K::default();
assert_eq!(BitAlloc4K::CAP, 4096); assert_eq!(BitAlloc4K::CAP, 4096);
ba.insert(0..4096);
for i in 0..4096 { for i in 0..4096 {
assert_eq!(ba.test(i), true); assert_eq!(ba.test(i), true);
} }

@ -37,6 +37,7 @@ extern crate arrayvec;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate simple_filesystem; extern crate simple_filesystem;
extern crate bit_allocator;
#[macro_use] // print! #[macro_use] // print!
mod io; mod io;
@ -107,13 +108,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
// }); // });
// } // }
loop{ loop {}
println!("init ...");
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
test_end!(); test_end!();
unreachable!(); unreachable!();

@ -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<Area>,
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<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.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(),
}
}
}

@ -1,4 +1,3 @@
pub use self::area_frame_allocator::AreaFrameAllocator;
pub use arch::paging::*; pub use arch::paging::*;
pub use self::stack_allocator::*; pub use self::stack_allocator::*;
pub use self::address::*; pub use self::address::*;
@ -12,18 +11,18 @@ use spin::{Mutex, MutexGuard};
use super::HEAP_ALLOCATOR; use super::HEAP_ALLOCATOR;
mod memory_set; mod memory_set;
mod area_frame_allocator;
pub mod heap_allocator; pub mod heap_allocator;
mod stack_allocator; mod stack_allocator;
mod address; mod address;
mod frame; mod frame;
pub static FRAME_ALLOCATOR: Mutex<Option<AreaFrameAllocator>> = Mutex::new(None); lazy_static! {
pub static STACK_ALLOCATOR: Mutex<Option<StackAllocator>> = Mutex::new(None); static ref FRAME_ALLOCATOR: Mutex<BitAlloc64K> = Mutex::new(BitAlloc64K::default());
}
static STACK_ALLOCATOR: Mutex<Option<StackAllocator>> = Mutex::new(None);
pub fn alloc_frame() -> Frame { pub fn alloc_frame() -> Frame {
FRAME_ALLOCATOR.lock() FRAME_ALLOCATOR.lock()
.as_mut().expect("frame allocator is not initialized")
.allocate_frame().expect("no more frame") .allocate_frame().expect("no more frame")
} }
@ -69,25 +68,49 @@ pub fn init(boot_info: BootInformation) -> MemorySet {
kernel_memory kernel_memory
} }
fn init_frame_allocator(boot_info: &BootInformation) { use bit_allocator::{BitAlloc64K, BitAlloc};
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() impl FrameAllocator for BitAlloc64K {
.filter(|s| s.is_allocated()).map(|s| s.start_address()).min().unwrap()); fn allocate_frame(&mut self) -> Option<Frame> {
let kernel_end = PhysAddr::from_kernel_virtual(elf_sections_tag.sections() self.alloc().map(|x| Frame { number: x })
.filter(|s| s.is_allocated()).map(|s| s.end_address()).max().unwrap() as usize); }
fn deallocate_frame(&mut self, frame: Frame) {
self.dealloc(frame.number);
}
}
let boot_info_start = PhysAddr(boot_info.start_address() as u64); fn init_frame_allocator(boot_info: &BootInformation) {
let boot_info_end = PhysAddr(boot_info.end_address() as u64); 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());
*FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new( let mut ba = FRAME_ALLOCATOR.lock();
kernel_start, kernel_end, for area in memory_areas {
boot_info_start, boot_info_end, ba.insert(to_range(area.start_address(), area.end_address()));
memory_map_tag.memory_areas(), }
)); 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<usize> {
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 { 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}; 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(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")); memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
debug!("{:#x?}", memory_set); debug!("{:#x?}", memory_set);
memory_set.switch(); memory_set.switch();

@ -27,13 +27,7 @@ pub fn init(mut ms: MemorySet) {
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new(); pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new();
extern fn idle_thread(arg: usize) -> ! { extern fn idle_thread(arg: usize) -> ! {
loop { loop {}
println!("idle ...");
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
} }
pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) { pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) {

Loading…
Cancel
Save