Initialise a bitmap allocator This function is unsafe because the caller must guarantee that the memory map and physical memory offset is correct.
(memory_map: &'static MemoryMap,
physical_memory_offset: VirtAddr)
| 101 | /// This function is unsafe because the caller must guarantee |
| 102 | /// that the memory map and physical memory offset is correct. |
| 103 | pub unsafe fn init(memory_map: &'static MemoryMap, |
| 104 | physical_memory_offset: VirtAddr) -> Self { |
| 105 | // get usable regions from memory map |
| 106 | let mut usable_regions = memory_map |
| 107 | .iter() |
| 108 | .filter(|r| r.region_type == MemoryRegionType::Usable); |
| 109 | |
| 110 | _ = usable_regions.next(); // Discard the first region |
| 111 | let region = usable_regions.next().unwrap(); |
| 112 | |
| 113 | let start_addr = region.range.start_addr(); |
| 114 | let end_addr = region.range.end_addr(); |
| 115 | let nframes = region.range.end_frame_number - region.range.start_frame_number; |
| 116 | let nlevels = num_levels_needed(nframes); |
| 117 | |
| 118 | let mut bitmap_virt_addr = [VirtAddr::new(0); FRAME_ALLOCATOR_MAX_LEVELS]; |
| 119 | let mut level_start_addr = start_addr; |
| 120 | let mut nbits = nframes; // Number of bits needed at each level |
| 121 | for level in 0..nlevels { |
| 122 | bitmap_virt_addr[level] = physical_memory_offset + level_start_addr; |
| 123 | let level_ptr = bitmap_virt_addr[level].as_mut_ptr() as *mut u32; |
| 124 | |
| 125 | let num_full_chunks = nbits >> 5; |
| 126 | for i in 0..num_full_chunks { |
| 127 | *(level_ptr.offset(i as isize)) = 0xFFFF_FFFF; |
| 128 | } |
| 129 | |
| 130 | // May need final part-filled chunk |
| 131 | let num_extra_bits = nbits & 31; |
| 132 | if num_extra_bits > 0 { |
| 133 | // Fill with ones, then shift to zero missing frames |
| 134 | // note: Missing frames correspond to high bits so shift right |
| 135 | *(level_ptr.offset(num_full_chunks as isize)) = |
| 136 | 0xFFFF_FFFF >> (32 - num_extra_bits); |
| 137 | } |
| 138 | |
| 139 | // Total number of chunks i.e. bits at next level |
| 140 | nbits = num_full_chunks + if num_extra_bits > 0 {1} else {0}; |
| 141 | |
| 142 | // Start address of the next level |
| 143 | level_start_addr += nbits * 4u64; |
| 144 | } |
| 145 | // Number of bytes needed to store all bitmaps |
| 146 | let bitmap_size_bytes = level_start_addr - start_addr; |
| 147 | // Round up number of frames needed by adding 4095 and dividing by 4096 |
| 148 | let bitmap_size_frames = (bitmap_size_bytes + 4095) >> 12; |
| 149 | |
| 150 | println!("Region: {:#016X} - {:#016X}", start_addr, end_addr); |
| 151 | println!("Frames: {} Levels: {} Reserved frames: {}", |
| 152 | nframes, nlevels, bitmap_size_frames); |
| 153 | |
| 154 | // Mark frames where bitmaps are stored as used |
| 155 | // - Clear low bits in bitmaps corresponding to the used frames |
| 156 | // - May need to clear multiple chunks and levels if the |
| 157 | // bitmap fills more than one chunk (32 frames). |
| 158 | let mut nbits = bitmap_size_frames; // Number of bits to clear |
| 159 | for level in 0..nlevels { |
| 160 | let ptr = bitmap_virt_addr[level].as_mut_ptr() as *mut u32; |
no test coverage detected