memory.rs
1 use x86_64::{ 2 structures::paging::PageTable, 3 structures::paging::OffsetPageTable, 4 structures::paging::{Page, PhysFrame, Mapper, Size4KiB, FrameAllocator}, 5 VirtAddr, 6 PhysAddr, 7 }; 8 use bootloader::bootinfo::MemoryMap; 9 use bootloader::bootinfo::MemoryRegionType; 10 11 pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { 12 unsafe { 13 let level_4_table = active_level_4_table(physical_memory_offset); 14 OffsetPageTable::new(level_4_table, physical_memory_offset) 15 } 16 } 17 18 pub unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) 19 -> &'static mut PageTable 20 { 21 use x86_64::registers::control::Cr3; 22 23 let (level_4_table_frame, _) = Cr3::read(); 24 25 let phys = level_4_table_frame.start_address(); 26 let virt = physical_memory_offset + phys.as_u64(); 27 let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); 28 29 unsafe { &mut *page_table_ptr } 30 } 31 32 pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_offset: VirtAddr) 33 -> Option<PhysAddr> 34 { 35 translate_addr_inner(addr, physical_memory_offset) 36 } 37 38 pub fn create_example_mapping( 39 page: Page, 40 mapper: &mut OffsetPageTable, 41 frame_allocator: &mut impl FrameAllocator<Size4KiB>, 42 ) { 43 use x86_64::structures::paging::PageTableFlags as Flags; 44 45 let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); 46 let flags = Flags::PRESENT | Flags::WRITABLE; 47 48 let map_to_result = unsafe { 49 mapper.map_to(page, frame, flags, frame_allocator) 50 }; 51 map_to_result.expect("map_to failed").flush(); 52 } 53 54 pub struct EmptyFrameAllocator; 55 56 unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator { 57 fn allocate_frame(&mut self) -> Option<PhysFrame> { 58 None 59 } 60 } 61 62 pub struct BootInfoFrameAllocator { 63 memory_map: &'static MemoryMap, 64 next: usize, 65 } 66 67 impl BootInfoFrameAllocator { 68 pub unsafe fn init(memory_map: &'static MemoryMap) -> Self { 69 BootInfoFrameAllocator { 70 memory_map, 71 next: 0, 72 } 73 } 74 75 fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> { 76 let regions = self.memory_map.iter(); 77 let usable_regions = regions 78 .filter(|r| r.region_type == MemoryRegionType::Usable); 79 let addr_ranges = usable_regions 80 .map(|r| r.range.start_addr()..r.range.end_addr()); 81 let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096)); 82 frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr))) 83 } 84 } 85 86 unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator { 87 fn allocate_frame(&mut self) -> Option<PhysFrame> { 88 let frame = self.usable_frames().nth(self.next); 89 self.next += 1; 90 frame 91 } 92 } 93 94 fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr) 95 -> Option<PhysAddr> 96 { 97 use x86_64::structures::paging::page_table::FrameError; 98 use x86_64::registers::control::Cr3; 99 100 let (level_4_table_frame, _) = Cr3::read(); 101 102 let table_indexes = [ 103 addr.p4_index(), addr.p3_index(), addr.p2_index(), addr.p1_index() 104 ]; 105 let mut frame = level_4_table_frame; 106 107 for &index in &table_indexes { 108 let virt = physical_memory_offset + frame.start_address().as_u64(); 109 let table_ptr: *const PageTable = virt.as_ptr(); 110 let table = unsafe { &*table_ptr }; 111 112 let entry = &table[index]; 113 frame = match entry.frame() { 114 Ok(frame) => frame, 115 Err(FrameError::FrameNotPresent) => return None, 116 Err(FrameError::HugeFrame) => panic!("huge pages not supported"), 117 }; 118 } 119 120 Some(frame.start_address() + u64::from(addr.page_offset())) 121 }