1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 16:16:16 +04:00

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

This commit is contained in:
WangRunji 2018-06-03 19:29:11 +08:00
parent 2762fded9c
commit f3d62a5b8f
6 changed files with 76 additions and 180 deletions

View File

@ -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"

View File

@ -10,6 +10,7 @@ pub trait BitAlloc: Default {
const CAP: usize;
fn alloc(&mut self) -> Option<usize>;
fn dealloc(&mut self, key: usize);
fn insert(&mut self, range: Range<usize>);
fn remove(&mut self, range: Range<usize>);
fn any(&self) -> bool;
fn test(&self, key: usize) -> bool;
@ -22,20 +23,12 @@ pub type BitAlloc1M = BitAllocCascade16<BitAlloc64K>;
pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>;
pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
#[derive(Default)]
pub struct BitAllocCascade16<T: BitAlloc> {
bitset: u16,
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> {
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.bitset.set_bit(i, true);
}
fn insert(&mut self, range: Range<usize>) {
self.for_range(range, |sub: &mut T, range| sub.insert(range));
}
fn remove(&mut self, range: Range<usize>) {
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<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
}
}
pub struct BitAlloc16(u16);
impl Default for BitAlloc16 {
fn default() -> Self {
BitAlloc16(0xffff)
impl<T: BitAlloc> BitAllocCascade16<T> {
fn for_range(&mut self, range: Range<usize>, f: impl Fn(&mut T, Range<usize>)) {
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<usize>) {
self.0.set_bits(range.clone(), 0xffff.get_bits(range));
}
fn remove(&mut self, range: Range<usize>) {
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);
}

View File

@ -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!();

View File

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

View File

@ -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<Option<AreaFrameAllocator>> = Mutex::new(None);
pub static STACK_ALLOCATOR: Mutex<Option<StackAllocator>> = Mutex::new(None);
lazy_static! {
static ref FRAME_ALLOCATOR: Mutex<BitAlloc64K> = Mutex::new(BitAlloc64K::default());
}
static STACK_ALLOCATOR: Mutex<Option<StackAllocator>> = 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<Frame> {
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 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 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 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()));
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(),
));
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 {
@ -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();

View File

@ -27,13 +27,7 @@ pub fn init(mut ms: MemorySet) {
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = 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<str>, data: &[u8]) {