1 use system_error::SystemError; 2 3 use crate::{ 4 arch::MMArch, 5 libs::{align::page_align_up, spinlock::SpinLock}, 6 mm::no_init::{pseudo_map_phys, pseudo_map_phys_ro, pseudo_unmap_phys}, 7 }; 8 9 use super::{allocator::page_frame::PageFrameCount, MemoryManagementArch, PhysAddr, VirtAddr}; 10 11 static SLOTS: SpinLock<[Slot; EarlyIoRemap::SLOT_CNT]> = 12 SpinLock::new([Slot::DEFAULT; EarlyIoRemap::SLOT_CNT]); 13 14 /// 早期IO映射机制 15 /// 16 /// 该机制在内存管理初始化之前,提供IO重映射的功能。 17 /// 18 /// ## 注意 19 /// 20 /// 该机制使用固定大小的slot来记录所有的映射, 21 /// 而这些映射空间是有限的,由MMArch::FIXMAP_SIZE指定 22 pub struct EarlyIoRemap; 23 24 impl EarlyIoRemap { 25 const SLOT_CNT: usize = MMArch::FIXMAP_SIZE / MMArch::PAGE_SIZE; 26 27 /// 把物理内存映射到虚拟内存中 28 /// 29 /// ## 说明 30 /// 31 /// 虚拟内存由early io remap机制自动分配。 32 /// 33 /// ## 参数 34 /// 35 /// - phys: 物理内存地址(需要按页对齐) 36 /// - size: 映射的内存大小 37 /// - read_only: 映射区与是否只读 38 /// 39 /// ## 返回值 40 /// 41 /// - 成功: (虚拟内存地址, 映射的内存大小) 42 /// - Err(SystemError::ENOMEM): 可用的slot不足 43 /// - Err(SystemError::EINVAL): 传入的物理地址没有对齐 44 #[allow(dead_code)] 45 pub fn map( 46 phys: PhysAddr, 47 size: usize, 48 read_only: bool, 49 ) -> Result<(VirtAddr, usize), SystemError> { 50 if phys.check_aligned(MMArch::PAGE_SIZE) == false { 51 return Err(SystemError::EINVAL); 52 } 53 54 // kdebug!("Early io remap:{phys:?}, size:{size}"); 55 56 let mut slot_guard = SLOTS.lock(); 57 58 let slot_count = PageFrameCount::from_bytes(page_align_up(size)) 59 .unwrap() 60 .data(); 61 // 寻找连续的slot 62 let mut start_slot = None; 63 for i in 0..(Self::SLOT_CNT - slot_count + 1) { 64 let mut is_continuous = true; 65 66 for j in 0..slot_count { 67 let slot_idx = i + j; 68 if slot_guard[slot_idx].start_idx.is_some() { 69 is_continuous = false; 70 break; 71 } 72 } 73 74 if is_continuous { 75 start_slot = Some(i); 76 break; 77 } 78 } 79 80 let start_slot = start_slot.ok_or(SystemError::ENOMEM)?; 81 let vaddr = Self::idx_to_virt(start_slot); 82 83 // kdebug!("start_slot:{start_slot}, vaddr: {vaddr:?}, slot_count: {slot_count:?}"); 84 let page_count = PageFrameCount::new(slot_count); 85 // 执行映射 86 if read_only { 87 unsafe { pseudo_map_phys_ro(vaddr, phys, page_count) } 88 } else { 89 unsafe { pseudo_map_phys(vaddr, phys, page_count) } 90 } 91 92 // kdebug!("map ok"); 93 94 // 更新slot信息 95 let map_size = slot_count * MMArch::PAGE_SIZE; 96 for i in 0..slot_count { 97 let slot_idx = start_slot + i; 98 slot_guard[slot_idx].start_idx = Some(start_slot as u32); 99 100 if i == 0 { 101 slot_guard[slot_idx].size = map_size as u32; 102 slot_guard[slot_idx].phys = phys; 103 } 104 } 105 106 return Ok((vaddr, map_size)); 107 } 108 109 /// 取消映射 110 /// 111 /// ## 参数 112 /// 113 /// - virt: 映射范围内的任意虚拟地址 114 /// 115 /// ## 返回值 116 /// 117 /// - Ok: 成功 118 /// - Err(SystemError::EINVAL): 传入的虚拟地址不在early io remap范围内, 119 /// 或者虚拟地址未映射 120 #[allow(dead_code)] 121 pub fn unmap(virt: VirtAddr) -> Result<(), SystemError> { 122 if virt < MMArch::FIXMAP_START_VADDR || virt >= MMArch::FIXMAP_END_VADDR { 123 return Err(SystemError::EINVAL); 124 } 125 126 let mut slot_guard = SLOTS.lock(); 127 let mut idx = None; 128 129 // 寻找虚拟地址对应的区域的第一个slot 130 for slot_idx in 0..Self::SLOT_CNT { 131 let slot = &mut slot_guard[slot_idx]; 132 if let Some(start_idx) = slot.start_idx { 133 if start_idx == slot_idx as u32 { 134 let vaddr_start = Self::idx_to_virt(start_idx as usize); 135 let vaddr_end = vaddr_start + slot.size as usize; 136 if vaddr_start <= virt && virt < vaddr_end { 137 // 找到区域了 138 idx = Some(slot_idx); 139 break; 140 } 141 } 142 } 143 } 144 145 let idx = idx.ok_or(SystemError::EINVAL)?; 146 147 let vaddr = Self::idx_to_virt(idx as usize); 148 let count = PageFrameCount::from_bytes(slot_guard[idx].size as usize).unwrap(); 149 150 // 取消映射 151 152 unsafe { pseudo_unmap_phys(vaddr, count) }; 153 154 for i in 0..count.data() { 155 let slot_idx = idx + i; 156 let slot = &mut slot_guard[slot_idx]; 157 *slot = Slot::DEFAULT; 158 } 159 160 return Ok(()); 161 } 162 163 /// 把slot下标转换为这个slot对应的虚拟地址 164 fn idx_to_virt(idx: usize) -> VirtAddr { 165 MMArch::FIXMAP_START_VADDR + idx * MMArch::PAGE_SIZE 166 } 167 } 168 169 #[derive(Debug, Clone, Copy)] 170 struct Slot { 171 /// 连续映射的起始槽位号 172 start_idx: Option<u32>, 173 /// 连续映射的区域大小(仅在起始槽位中设置) 174 size: u32, 175 /// 映射的起始物理地址 176 phys: PhysAddr, 177 } 178 179 impl Slot { 180 const DEFAULT: Self = Self { 181 start_idx: None, 182 size: 0, 183 phys: PhysAddr::new(0), 184 }; 185 } 186