xref: /DragonOS/kernel/src/mm/early_ioremap.rs (revision 74ffde667e5e7f4ac8ce6d5a5ec2c1403f36cbb0)
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