Skip to content

Commit

Permalink
Avoid generic impl trait parameters in BootInfoFrameAllocator
Browse files Browse the repository at this point in the history
This makes it very hard to put the BootInfoFrameAllocator in a static, e.g. for accessing it from a page fault handler. See #593 for more information.
  • Loading branch information
phil-opp committed Apr 30, 2019
1 parent 247af45 commit 66324dd
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
blog_os::init();

let mut mapper = unsafe { memory::init(boot_info.physical_memory_offset) };
let mut frame_allocator = memory::init_frame_allocator(&boot_info.memory_map);
let mut frame_allocator = memory::BootInfoFrameAllocator::init(&boot_info.memory_map);

// map a previously unmapped page
let page = Page::containing_address(VirtAddr::new(0xdeadbeaf000));
Expand Down
62 changes: 34 additions & 28 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,6 @@ pub unsafe fn init(physical_memory_offset: u64) -> impl MapperAllSizes {
MappedPageTable::new(level_4_table, phys_to_virt)
}

/// Create a FrameAllocator from the passed memory map
pub fn init_frame_allocator(
memory_map: &'static MemoryMap,
) -> BootInfoFrameAllocator<impl Iterator<Item = PhysFrame>> {
// get usable regions from memory map
let regions = memory_map
.iter()
.filter(|r| r.region_type == MemoryRegionType::Usable);
// map each region to its address range
let addr_ranges = regions.map(|r| r.range.start_addr()..r.range.end_addr());
// transform to an iterator of frame start addresses
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
// create `PhysFrame` types from the start addresses
let frames = frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)));

BootInfoFrameAllocator { frames }
}

/// Returns a mutable reference to the active level 4 table.
///
/// This function is unsafe because the caller must guarantee that the
Expand Down Expand Up @@ -83,18 +65,42 @@ impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
}
}

pub struct BootInfoFrameAllocator<I>
where
I: Iterator<Item = PhysFrame>,
{
frames: I,
pub struct BootInfoFrameAllocator {
memory_map: &'static MemoryMap,
last_yielded_frame: PhysFrame,
}

impl BootInfoFrameAllocator {
/// Create a FrameAllocator from the passed memory map.
pub fn init(memory_map: &'static MemoryMap) -> Self {
BootInfoFrameAllocator {
memory_map,
last_yielded_frame: PhysFrame::containing_address(PhysAddr::new(0)),
}
}

/// Returns an iterator over the usable frames specified in the memory map.
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
// get usable regions from memory map
let regions = self.memory_map.iter();
let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
// map each region to its address range
let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());
// transform to an iterator of frame start addresses
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
// create `PhysFrame` types from the start addresses
frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
}
}

impl<I> FrameAllocator<Size4KiB> for BootInfoFrameAllocator<I>
where
I: Iterator<Item = PhysFrame>,
{
impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
self.frames.next()
let usable_frames = self.usable_frames();
let mut frames = usable_frames.filter(|frame| frame > &self.last_yielded_frame);
let frame = frames.next();
if let Some(frame) = frame {
self.last_yielded_frame = frame.clone();
}
frame
}
}

0 comments on commit 66324dd

Please sign in to comment.