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