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:
parent
2762fded9c
commit
f3d62a5b8f
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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!();
|
||||
|
@ -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 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();
|
||||
|
@ -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]) {
|
||||
|
Loading…
Reference in New Issue
Block a user