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_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 /// 38 /// ## 返回值 39 /// 40 /// - 成功: (虚拟内存地址, 映射的内存大小) 41 /// - Err(SystemError::ENOMEM): 可用的slot不足 42 /// - Err(SystemError::EINVAL): 传入的物理地址没有对齐 43 #[allow(dead_code)] 44 pub fn map(phys: PhysAddr, size: usize) -> Result<(VirtAddr, usize), SystemError> { 45 if phys.check_aligned(MMArch::PAGE_SIZE) == false { 46 return Err(SystemError::EINVAL); 47 } 48 49 let mut slot_guard = SLOTS.lock(); 50 51 let slot_count = PageFrameCount::from_bytes(page_align_up(size)) 52 .unwrap() 53 .data(); 54 // 寻找连续的slot 55 let mut start_slot = None; 56 for i in 0..(Self::SLOT_CNT - slot_count + 1) { 57 let mut is_continuous = true; 58 59 for j in 0..slot_count { 60 let slot_idx = i + j; 61 if slot_guard[slot_idx].start_idx.is_some() { 62 is_continuous = false; 63 break; 64 } 65 } 66 67 if is_continuous { 68 start_slot = Some(i); 69 break; 70 } 71 } 72 73 let start_slot = start_slot.ok_or(SystemError::ENOMEM)?; 74 let vaddr = Self::idx_to_virt(start_slot); 75 // 执行映射 76 unsafe { pseudo_map_phys(vaddr, phys, PageFrameCount::new(slot_count)) } 77 78 // 更新slot信息 79 let map_size = slot_count * MMArch::PAGE_SIZE; 80 for i in 0..slot_count { 81 let slot_idx = start_slot + i; 82 slot_guard[slot_idx].start_idx = Some(start_slot as u32); 83 84 if i == 0 { 85 slot_guard[slot_idx].size = map_size as u32; 86 slot_guard[slot_idx].phys = phys; 87 } 88 } 89 90 return Ok((vaddr, map_size)); 91 } 92 93 /// 取消映射 94 /// 95 /// ## 参数 96 /// 97 /// - virt: 映射范围内的任意虚拟地址 98 /// 99 /// ## 返回值 100 /// 101 /// - Ok: 成功 102 /// - Err(SystemError::EINVAL): 传入的虚拟地址不在early io remap范围内, 103 /// 或者虚拟地址未映射 104 #[allow(dead_code)] 105 pub fn unmap(virt: VirtAddr) -> Result<(), SystemError> { 106 if virt < MMArch::FIXMAP_START_VADDR || virt >= MMArch::FIXMAP_END_VADDR { 107 return Err(SystemError::EINVAL); 108 } 109 110 let mut slot_guard = SLOTS.lock(); 111 let mut idx = None; 112 113 // 寻找虚拟地址对应的区域的第一个slot 114 for slot_idx in 0..Self::SLOT_CNT { 115 let slot = &mut slot_guard[slot_idx]; 116 if let Some(start_idx) = slot.start_idx { 117 if start_idx == slot_idx as u32 { 118 let vaddr_start = Self::idx_to_virt(start_idx as usize); 119 let vaddr_end = vaddr_start + slot.size as usize; 120 if vaddr_start <= virt && virt < vaddr_end { 121 // 找到区域了 122 idx = Some(slot_idx); 123 break; 124 } 125 } 126 } 127 } 128 129 let idx = idx.ok_or(SystemError::EINVAL)?; 130 131 let vaddr = Self::idx_to_virt(idx as usize); 132 let count = PageFrameCount::from_bytes(slot_guard[idx].size as usize).unwrap(); 133 134 // 取消映射 135 136 unsafe { pseudo_unmap_phys(vaddr, count) }; 137 138 for i in 0..count.data() { 139 let slot_idx = idx + i; 140 let slot = &mut slot_guard[slot_idx]; 141 *slot = Slot::DEFAULT; 142 } 143 144 todo!() 145 } 146 147 /// 把slot下标转换为这个slot对应的虚拟地址 148 fn idx_to_virt(idx: usize) -> VirtAddr { 149 MMArch::FIXMAP_START_VADDR + idx * MMArch::PAGE_SIZE 150 } 151 } 152 153 #[derive(Debug, Clone, Copy)] 154 struct Slot { 155 /// 连续映射的起始槽位号 156 start_idx: Option<u32>, 157 /// 连续映射的区域大小(仅在起始槽位中设置) 158 size: u32, 159 /// 映射的起始物理地址 160 phys: PhysAddr, 161 } 162 163 impl Slot { 164 const DEFAULT: Self = Self { 165 start_idx: None, 166 size: 0, 167 phys: PhysAddr::new(0), 168 }; 169 } 170