xref: /DragonOS/kernel/src/mm/early_ioremap.rs (revision b5b571e02693d91eb6918d3b7561e088c3e7ee81)
174ffde66SLoGin use system_error::SystemError;
274ffde66SLoGin 
374ffde66SLoGin use crate::{
474ffde66SLoGin     arch::MMArch,
592849878SLoGin     libs::{
692849878SLoGin         align::{page_align_down, page_align_up},
792849878SLoGin         spinlock::SpinLock,
892849878SLoGin     },
97a29d4fcSLoGin     mm::no_init::{pseudo_map_phys, pseudo_map_phys_ro, pseudo_unmap_phys},
1074ffde66SLoGin };
1174ffde66SLoGin 
1274ffde66SLoGin use super::{allocator::page_frame::PageFrameCount, MemoryManagementArch, PhysAddr, VirtAddr};
1374ffde66SLoGin 
1474ffde66SLoGin static SLOTS: SpinLock<[Slot; EarlyIoRemap::SLOT_CNT]> =
1574ffde66SLoGin     SpinLock::new([Slot::DEFAULT; EarlyIoRemap::SLOT_CNT]);
1674ffde66SLoGin 
1774ffde66SLoGin /// 早期IO映射机制
1874ffde66SLoGin ///
1974ffde66SLoGin /// 该机制在内存管理初始化之前,提供IO重映射的功能。
2074ffde66SLoGin ///
2174ffde66SLoGin /// ## 注意
2274ffde66SLoGin ///
2374ffde66SLoGin /// 该机制使用固定大小的slot来记录所有的映射,
2474ffde66SLoGin /// 而这些映射空间是有限的,由MMArch::FIXMAP_SIZE指定
2574ffde66SLoGin pub struct EarlyIoRemap;
2674ffde66SLoGin 
2774ffde66SLoGin impl EarlyIoRemap {
2874ffde66SLoGin     const SLOT_CNT: usize = MMArch::FIXMAP_SIZE / MMArch::PAGE_SIZE;
2974ffde66SLoGin 
3092849878SLoGin     /// 把物理内存映射到虚拟内存中(物理地址不要求对齐
3192849878SLoGin     ///
3292849878SLoGin     /// ## 参数
3392849878SLoGin     ///
3492849878SLoGin     /// - phys: 物理内存地址(不需要对齐)
3592849878SLoGin     /// - size: 映射的内存大小
3692849878SLoGin     /// - read_only: 映射区与是否只读
3792849878SLoGin     ///
3892849878SLoGin     /// ## 返回值
3992849878SLoGin     ///
4092849878SLoGin     /// - 成功: (phys对应的虚拟内存地址)
4192849878SLoGin     /// - Err(SystemError::ENOMEM): 可用的slot不足
4292849878SLoGin     #[allow(dead_code)]
4392849878SLoGin     pub fn map_not_aligned(
4492849878SLoGin         mut phys: PhysAddr,
4592849878SLoGin         mut size: usize,
4692849878SLoGin         read_only: bool,
4792849878SLoGin     ) -> Result<VirtAddr, SystemError> {
4892849878SLoGin         // kdebug!("map not aligned phys:{phys:?}, size:{size:?}, read_only:{read_only:?}");
4992849878SLoGin 
5092849878SLoGin         let offset = phys.data() - page_align_down(phys.data());
5192849878SLoGin         size += offset;
5292849878SLoGin         phys -= offset;
5392849878SLoGin 
5492849878SLoGin         let (map_vaddr, _) = Self::map(phys, size, read_only)?;
5592849878SLoGin         return Ok(map_vaddr + offset);
5692849878SLoGin     }
5792849878SLoGin 
5874ffde66SLoGin     /// 把物理内存映射到虚拟内存中
5974ffde66SLoGin     ///
6074ffde66SLoGin     /// ## 说明
6174ffde66SLoGin     ///
6274ffde66SLoGin     /// 虚拟内存由early io remap机制自动分配。
6374ffde66SLoGin     ///
6474ffde66SLoGin     /// ## 参数
6574ffde66SLoGin     ///
6674ffde66SLoGin     /// - phys: 物理内存地址(需要按页对齐)
6774ffde66SLoGin     /// - size: 映射的内存大小
687a29d4fcSLoGin     /// - read_only: 映射区与是否只读
6974ffde66SLoGin     ///
7074ffde66SLoGin     /// ## 返回值
7174ffde66SLoGin     ///
7274ffde66SLoGin     /// - 成功: (虚拟内存地址, 映射的内存大小)
7374ffde66SLoGin     /// - Err(SystemError::ENOMEM): 可用的slot不足
7474ffde66SLoGin     /// - Err(SystemError::EINVAL): 传入的物理地址没有对齐
7574ffde66SLoGin     #[allow(dead_code)]
767a29d4fcSLoGin     pub fn map(
777a29d4fcSLoGin         phys: PhysAddr,
787a29d4fcSLoGin         size: usize,
797a29d4fcSLoGin         read_only: bool,
807a29d4fcSLoGin     ) -> Result<(VirtAddr, usize), SystemError> {
81*b5b571e0SLoGin         if !phys.check_aligned(MMArch::PAGE_SIZE) {
8274ffde66SLoGin             return Err(SystemError::EINVAL);
8374ffde66SLoGin         }
8474ffde66SLoGin 
857a29d4fcSLoGin         // kdebug!("Early io remap:{phys:?}, size:{size}");
867a29d4fcSLoGin 
8774ffde66SLoGin         let mut slot_guard = SLOTS.lock();
8874ffde66SLoGin 
8974ffde66SLoGin         let slot_count = PageFrameCount::from_bytes(page_align_up(size))
9074ffde66SLoGin             .unwrap()
9174ffde66SLoGin             .data();
9274ffde66SLoGin         // 寻找连续的slot
9374ffde66SLoGin         let mut start_slot = None;
9474ffde66SLoGin         for i in 0..(Self::SLOT_CNT - slot_count + 1) {
9574ffde66SLoGin             let mut is_continuous = true;
9674ffde66SLoGin 
9774ffde66SLoGin             for j in 0..slot_count {
9874ffde66SLoGin                 let slot_idx = i + j;
9974ffde66SLoGin                 if slot_guard[slot_idx].start_idx.is_some() {
10074ffde66SLoGin                     is_continuous = false;
10174ffde66SLoGin                     break;
10274ffde66SLoGin                 }
10374ffde66SLoGin             }
10474ffde66SLoGin 
10574ffde66SLoGin             if is_continuous {
10674ffde66SLoGin                 start_slot = Some(i);
10774ffde66SLoGin                 break;
10874ffde66SLoGin             }
10974ffde66SLoGin         }
11074ffde66SLoGin 
11174ffde66SLoGin         let start_slot = start_slot.ok_or(SystemError::ENOMEM)?;
11274ffde66SLoGin         let vaddr = Self::idx_to_virt(start_slot);
1137a29d4fcSLoGin 
1147a29d4fcSLoGin         // kdebug!("start_slot:{start_slot}, vaddr: {vaddr:?}, slot_count: {slot_count:?}");
1157a29d4fcSLoGin         let page_count = PageFrameCount::new(slot_count);
11674ffde66SLoGin         // 执行映射
1177a29d4fcSLoGin         if read_only {
1187a29d4fcSLoGin             unsafe { pseudo_map_phys_ro(vaddr, phys, page_count) }
1197a29d4fcSLoGin         } else {
1207a29d4fcSLoGin             unsafe { pseudo_map_phys(vaddr, phys, page_count) }
1217a29d4fcSLoGin         }
1227a29d4fcSLoGin 
1237a29d4fcSLoGin         // kdebug!("map ok");
12474ffde66SLoGin 
12574ffde66SLoGin         // 更新slot信息
12674ffde66SLoGin         let map_size = slot_count * MMArch::PAGE_SIZE;
12774ffde66SLoGin         for i in 0..slot_count {
12874ffde66SLoGin             let slot_idx = start_slot + i;
12974ffde66SLoGin             slot_guard[slot_idx].start_idx = Some(start_slot as u32);
13074ffde66SLoGin 
13174ffde66SLoGin             if i == 0 {
13274ffde66SLoGin                 slot_guard[slot_idx].size = map_size as u32;
13374ffde66SLoGin                 slot_guard[slot_idx].phys = phys;
13474ffde66SLoGin             }
13574ffde66SLoGin         }
13674ffde66SLoGin 
13774ffde66SLoGin         return Ok((vaddr, map_size));
13874ffde66SLoGin     }
13974ffde66SLoGin 
14074ffde66SLoGin     /// 取消映射
14174ffde66SLoGin     ///
14274ffde66SLoGin     /// ## 参数
14374ffde66SLoGin     ///
14474ffde66SLoGin     /// - virt: 映射范围内的任意虚拟地址
14574ffde66SLoGin     ///
14674ffde66SLoGin     /// ## 返回值
14774ffde66SLoGin     ///
14874ffde66SLoGin     /// - Ok: 成功
14974ffde66SLoGin     /// - Err(SystemError::EINVAL): 传入的虚拟地址不在early io remap范围内,
15074ffde66SLoGin     ///     或者虚拟地址未映射
15174ffde66SLoGin     #[allow(dead_code)]
15274ffde66SLoGin     pub fn unmap(virt: VirtAddr) -> Result<(), SystemError> {
15374ffde66SLoGin         if virt < MMArch::FIXMAP_START_VADDR || virt >= MMArch::FIXMAP_END_VADDR {
15474ffde66SLoGin             return Err(SystemError::EINVAL);
15574ffde66SLoGin         }
15674ffde66SLoGin 
15774ffde66SLoGin         let mut slot_guard = SLOTS.lock();
15874ffde66SLoGin         let mut idx = None;
15974ffde66SLoGin 
16074ffde66SLoGin         // 寻找虚拟地址对应的区域的第一个slot
16174ffde66SLoGin         for slot_idx in 0..Self::SLOT_CNT {
16274ffde66SLoGin             let slot = &mut slot_guard[slot_idx];
16374ffde66SLoGin             if let Some(start_idx) = slot.start_idx {
16474ffde66SLoGin                 if start_idx == slot_idx as u32 {
16574ffde66SLoGin                     let vaddr_start = Self::idx_to_virt(start_idx as usize);
16674ffde66SLoGin                     let vaddr_end = vaddr_start + slot.size as usize;
16774ffde66SLoGin                     if vaddr_start <= virt && virt < vaddr_end {
16874ffde66SLoGin                         // 找到区域了
16974ffde66SLoGin                         idx = Some(slot_idx);
17074ffde66SLoGin                         break;
17174ffde66SLoGin                     }
17274ffde66SLoGin                 }
17374ffde66SLoGin             }
17474ffde66SLoGin         }
17574ffde66SLoGin 
17674ffde66SLoGin         let idx = idx.ok_or(SystemError::EINVAL)?;
17774ffde66SLoGin 
178*b5b571e0SLoGin         let vaddr = Self::idx_to_virt(idx);
17974ffde66SLoGin         let count = PageFrameCount::from_bytes(slot_guard[idx].size as usize).unwrap();
18074ffde66SLoGin 
18174ffde66SLoGin         // 取消映射
18274ffde66SLoGin         unsafe { pseudo_unmap_phys(vaddr, count) };
18374ffde66SLoGin 
18474ffde66SLoGin         for i in 0..count.data() {
18574ffde66SLoGin             let slot_idx = idx + i;
18674ffde66SLoGin             let slot = &mut slot_guard[slot_idx];
18774ffde66SLoGin             *slot = Slot::DEFAULT;
18874ffde66SLoGin         }
18974ffde66SLoGin 
1907a29d4fcSLoGin         return Ok(());
19174ffde66SLoGin     }
19274ffde66SLoGin 
19374ffde66SLoGin     /// 把slot下标转换为这个slot对应的虚拟地址
19474ffde66SLoGin     fn idx_to_virt(idx: usize) -> VirtAddr {
19574ffde66SLoGin         MMArch::FIXMAP_START_VADDR + idx * MMArch::PAGE_SIZE
19674ffde66SLoGin     }
19774ffde66SLoGin }
19874ffde66SLoGin 
19974ffde66SLoGin #[derive(Debug, Clone, Copy)]
20074ffde66SLoGin struct Slot {
20174ffde66SLoGin     /// 连续映射的起始槽位号
20274ffde66SLoGin     start_idx: Option<u32>,
20374ffde66SLoGin     /// 连续映射的区域大小(仅在起始槽位中设置)
20474ffde66SLoGin     size: u32,
20574ffde66SLoGin     /// 映射的起始物理地址
20674ffde66SLoGin     phys: PhysAddr,
20774ffde66SLoGin }
20874ffde66SLoGin 
20974ffde66SLoGin impl Slot {
21074ffde66SLoGin     const DEFAULT: Self = Self {
21174ffde66SLoGin         start_idx: None,
21274ffde66SLoGin         size: 0,
21374ffde66SLoGin         phys: PhysAddr::new(0),
21474ffde66SLoGin     };
21574ffde66SLoGin }
216