-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3e2af53
commit 8590d9f
Showing
5 changed files
with
147 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use x86_64::{ | ||
structures::paging::{Page, PhysFrame, Mapper, Size4KiB, FrameAllocator, OffsetPageTable, PageTable}, | ||
PhysAddr, VirtAddr, | ||
}; | ||
use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; | ||
|
||
/// Initialize a new OffsetPageTable. | ||
/// | ||
/// This function is unsafe because the caller must guarantee that the | ||
/// complete physical memory is mapped to virtual memory at the passed | ||
/// `physical_memory_offset`. Also, this function must be only called once | ||
/// to avoid aliasing `&mut` references (which is undefined behavior). | ||
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { | ||
let level_4_table = active_level_4_table(physical_memory_offset); | ||
OffsetPageTable::new(level_4_table, physical_memory_offset) | ||
} | ||
|
||
/// Returns a mutable reference to the active level 4 table. | ||
/// | ||
/// This function is unsafe because the caller must guarantee that the | ||
/// complete physical memory is mapped to virtual memory at the passed | ||
/// `physical_memory_offset`. Also, this function must be only called once | ||
/// to avoid aliasing `&mut` references (which is undefined behavior). | ||
pub unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) | ||
-> &'static mut PageTable | ||
{ | ||
use x86_64::registers::control::Cr3; | ||
|
||
let (level_4_table_frame, _) = Cr3::read(); | ||
|
||
let phys = level_4_table_frame.start_address(); | ||
let virt = physical_memory_offset + phys.as_u64(); | ||
let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); | ||
|
||
&mut *page_table_ptr // unsafe | ||
} | ||
|
||
/// Creates an example mapping for the given page to frame `0xb8000`. | ||
pub fn create_example_mapping( | ||
page: Page, | ||
mapper: &mut OffsetPageTable, | ||
frame_allocator: &mut impl FrameAllocator<Size4KiB>, | ||
) { | ||
use x86_64::structures::paging::PageTableFlags as Flags; | ||
|
||
let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); | ||
let flags = Flags::PRESENT | Flags::WRITABLE; | ||
|
||
let map_to_result = unsafe { | ||
// FIXME: this is not safe, we do it only for testing | ||
mapper.map_to(page, frame, flags, frame_allocator) | ||
}; | ||
map_to_result.expect("map_to failed").flush(); | ||
} | ||
|
||
/// A FrameAllocator that returns usable frames from the bootloader's memory map. | ||
pub struct BootInfoFrameAllocator { | ||
memory_map: &'static MemoryMap, | ||
next: usize, | ||
} | ||
|
||
impl BootInfoFrameAllocator { | ||
/// Create a FrameAllocator from the passed memory map. | ||
/// | ||
/// This function is unsafe because the caller must guarantee that the passed | ||
/// memory map is valid. The main requirement is that all frames that are marked | ||
/// as `USABLE` in it are really unused. | ||
pub unsafe fn init(memory_map: &'static MemoryMap) -> Self { | ||
BootInfoFrameAllocator { | ||
memory_map, | ||
next: 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))) | ||
} | ||
} | ||
|
||
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator { | ||
fn allocate_frame(&mut self) -> Option<PhysFrame> { | ||
let frame = self.usable_frames().nth(self.next); | ||
self.next += 1; | ||
frame | ||
} | ||
} |