xref: /DragonOS/kernel/src/mm/mmio_buddy.rs (revision 2eab6dd743e94a86a685f1f3c01e599adf86610a)
10102d69fSLoGin use crate::libs::align::{page_align_down, page_align_up};
2a7eb62a4Shoumkh use crate::libs::spinlock::{SpinLock, SpinLockGuard};
340fe15e0SLoGin use crate::mm::kernel_mapper::KernelMapper;
423ef2b33SLoGin use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
5*2eab6dd7S曾俊 use crate::mm::{MMArch, MemoryManagementArch};
61496ba7bSLoGin use crate::process::ProcessManager;
7*2eab6dd7S曾俊 
840fe15e0SLoGin use alloc::{collections::LinkedList, vec::Vec};
940fe15e0SLoGin use core::mem;
1040fe15e0SLoGin use core::mem::MaybeUninit;
1123ef2b33SLoGin use core::sync::atomic::{AtomicBool, Ordering};
12*2eab6dd7S曾俊 use log::{debug, error, info, warn};
1391e9d4abSLoGin use system_error::SystemError;
1440fe15e0SLoGin 
15370472f7SLoGin use super::page::{PageFlags, PAGE_4K_SIZE};
162dd9f0c7SLoGin use super::{PhysAddr, VirtAddr};
17c2481452Shoumkh 
18c2481452Shoumkh // 最大的伙伴块的幂
1923ef2b33SLoGin const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT as u32;
20c2481452Shoumkh // 最小的伙伴块的幂
2123ef2b33SLoGin const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT as u32;
22c2481452Shoumkh // 内存池数组的范围
23c2481452Shoumkh const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
24c2481452Shoumkh 
2540fe15e0SLoGin const PAGE_1G_SIZE: usize = 1 << 30;
2640fe15e0SLoGin 
2740fe15e0SLoGin static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
2840fe15e0SLoGin 
297ae679ddSLoGin pub fn mmio_pool() -> &'static MmioBuddyMemPool {
307ae679ddSLoGin     unsafe { __MMIO_POOL.as_ref().unwrap() }
31c2481452Shoumkh }
32c2481452Shoumkh 
33c2481452Shoumkh pub enum MmioResult {
34c2481452Shoumkh     SUCCESS,
35c2481452Shoumkh     EINVAL,
36c2481452Shoumkh     ENOFOUND,
37c2481452Shoumkh     WRONGEXP,
38c2481452Shoumkh     ISEMPTY,
39c2481452Shoumkh }
40c2481452Shoumkh 
41c2481452Shoumkh /// @brief buddy内存池
4240fe15e0SLoGin #[derive(Debug)]
43c2481452Shoumkh pub struct MmioBuddyMemPool {
4440fe15e0SLoGin     pool_start_addr: VirtAddr,
4540fe15e0SLoGin     pool_size: usize,
46c2481452Shoumkh     free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
47c2481452Shoumkh }
4840fe15e0SLoGin 
49c2481452Shoumkh impl MmioBuddyMemPool {
50453452ccSLoGin     #[inline(never)]
51c2481452Shoumkh     fn new() -> Self {
5240fe15e0SLoGin         let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
5340fe15e0SLoGin             MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
5440fe15e0SLoGin         for i in 0..MMIO_BUDDY_REGION_COUNT {
5540fe15e0SLoGin             free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
5640fe15e0SLoGin         }
5740fe15e0SLoGin         let free_regions = unsafe {
5840fe15e0SLoGin             mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
5940fe15e0SLoGin                 free_regions,
6040fe15e0SLoGin             )
61c2481452Shoumkh         };
6240fe15e0SLoGin 
6340fe15e0SLoGin         let pool = MmioBuddyMemPool {
6423ef2b33SLoGin             pool_start_addr: MMArch::MMIO_BASE,
6523ef2b33SLoGin             pool_size: MMArch::MMIO_SIZE,
6640fe15e0SLoGin             free_regions,
6740fe15e0SLoGin         };
6823ef2b33SLoGin 
6923ef2b33SLoGin         assert!(pool.pool_start_addr.data() % PAGE_1G_SIZE == 0);
70*2eab6dd7S曾俊         debug!("MMIO buddy pool init: created");
7140fe15e0SLoGin 
7223ef2b33SLoGin         let mut vaddr_base = MMArch::MMIO_BASE;
7323ef2b33SLoGin         let mut remain_size = MMArch::MMIO_SIZE;
74*2eab6dd7S曾俊         debug!(
7523ef2b33SLoGin             "BASE: {:?}, TOP: {:?}, size: {:?}",
7623ef2b33SLoGin             MMArch::MMIO_BASE,
7723ef2b33SLoGin             MMArch::MMIO_TOP,
7823ef2b33SLoGin             MMArch::MMIO_SIZE
7923ef2b33SLoGin         );
8023ef2b33SLoGin 
8123ef2b33SLoGin         for shift in (PAGE_4K_SHIFT..=PAGE_1G_SHIFT).rev() {
8223ef2b33SLoGin             if remain_size & (1 << shift) != 0 {
8323ef2b33SLoGin                 let ok = pool.give_back_block(vaddr_base, shift as u32).is_ok();
8423ef2b33SLoGin                 if ok {
8523ef2b33SLoGin                     vaddr_base += 1 << shift;
8623ef2b33SLoGin                     remain_size -= 1 << shift;
8723ef2b33SLoGin                 } else {
8840fe15e0SLoGin                     panic!("MMIO buddy pool init failed");
8940fe15e0SLoGin                 }
9040fe15e0SLoGin             }
9140fe15e0SLoGin         }
9223ef2b33SLoGin 
93*2eab6dd7S曾俊         debug!("MMIO buddy pool init success");
9440fe15e0SLoGin         return pool;
95c2481452Shoumkh     }
96c2481452Shoumkh 
97c2481452Shoumkh     /// @brief 创建新的地址区域结构体
98c2481452Shoumkh     ///
99c2481452Shoumkh     /// @param vaddr 虚拟地址
100c2481452Shoumkh     ///
101c2481452Shoumkh     /// @return 创建好的地址区域结构体
10240fe15e0SLoGin     fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
103*2eab6dd7S曾俊         // debug!("create_region for vaddr: {vaddr:?}");
10440fe15e0SLoGin 
10540fe15e0SLoGin         let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
10640fe15e0SLoGin 
107*2eab6dd7S曾俊         // debug!("create_region for vaddr: {vaddr:?} OK!!!");
108c2481452Shoumkh         return region;
109c2481452Shoumkh     }
110c2481452Shoumkh 
111c2481452Shoumkh     /// @brief 将内存块归还给buddy
112c2481452Shoumkh     ///
113c2481452Shoumkh     /// @param vaddr 虚拟地址
114c2481452Shoumkh     ///
115c2481452Shoumkh     /// @param exp 内存空间的大小(2^exp)
116c2481452Shoumkh     ///
117c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
118c2481452Shoumkh     ///
119c2481452Shoumkh     /// @return Ok(i32) 返回0
120c2481452Shoumkh     ///
121676b8ef6SMork     /// @return Err(SystemError) 返回错误码
12240fe15e0SLoGin     fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
123c2481452Shoumkh         // 确保内存对齐,低位都要为0
12440fe15e0SLoGin         if (vaddr.data() & ((1 << exp) - 1)) != 0 {
125676b8ef6SMork             return Err(SystemError::EINVAL);
126c2481452Shoumkh         }
12740fe15e0SLoGin         let region: MmioBuddyAddrRegion = self.create_region(vaddr);
128c2481452Shoumkh         // 加入buddy
12940fe15e0SLoGin         let mut list_guard = self.free_regions[exp2index(exp)].lock();
13040fe15e0SLoGin 
13140fe15e0SLoGin         self.push_block(region, &mut list_guard);
132c2481452Shoumkh         return Ok(0);
133c2481452Shoumkh     }
134c2481452Shoumkh 
135c2481452Shoumkh     /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中
136c2481452Shoumkh     ///
137c2481452Shoumkh     /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
138c2481452Shoumkh     ///
139c2481452Shoumkh     /// @param exp 要被分割的地址区域的大小的幂
140c2481452Shoumkh     ///
141c2481452Shoumkh     /// @param list_guard 【exp-1】对应的链表
142a7eb62a4Shoumkh     fn split_block(
143c2481452Shoumkh         &self,
14440fe15e0SLoGin         region: MmioBuddyAddrRegion,
145c2481452Shoumkh         exp: u32,
146c2481452Shoumkh         low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
147c2481452Shoumkh     ) {
14840fe15e0SLoGin         let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
14940fe15e0SLoGin         let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
150a7eb62a4Shoumkh         self.push_block(region, low_list_guard);
151a7eb62a4Shoumkh         self.push_block(new_region, low_list_guard);
152c2481452Shoumkh     }
153c2481452Shoumkh 
154c2481452Shoumkh     /// @brief 从buddy中申请一块指定大小的内存区域
155c2481452Shoumkh     ///
156c2481452Shoumkh     /// @param exp 要申请的内存块的大小的幂(2^exp)
157c2481452Shoumkh     ///
158c2481452Shoumkh     /// @param list_guard exp对应的链表
159c2481452Shoumkh     ///
16040fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
161c2481452Shoumkh     ///
162c2481452Shoumkh     /// @return Err(MmioResult)
163c2481452Shoumkh     /// - 没有满足要求的内存块时,返回ENOFOUND
164c2481452Shoumkh     /// - 申请的内存块大小超过合法范围,返回WRONGEXP
165c2481452Shoumkh     /// - 调用函数出错时,返回出错函数对应错误码
166a7eb62a4Shoumkh     fn query_addr_region(
167c2481452Shoumkh         &self,
168c2481452Shoumkh         exp: u32,
169c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
17040fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
171c2481452Shoumkh         // 申请范围错误
172b5b571e0SLoGin         if !(MMIO_BUDDY_MIN_EXP..=MMIO_BUDDY_MAX_EXP).contains(&exp) {
173*2eab6dd7S曾俊             debug!("query_addr_region: exp wrong");
174c2481452Shoumkh             return Err(MmioResult::WRONGEXP);
175c2481452Shoumkh         }
176c2481452Shoumkh         // 没有恰好符合要求的内存块
177c2481452Shoumkh         // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】
178c2481452Shoumkh         if list_guard.num_free == 0 {
179c2481452Shoumkh             // 找到最小符合申请范围的内存块
180c2481452Shoumkh             // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp
181c2481452Shoumkh             for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
182ef9f9732Shoumkh                 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
183b5b571e0SLoGin                     &mut self.free_regions[exp2index(e)].lock();
184ef9f9732Shoumkh                 if pop_list.num_free == 0 {
185c2481452Shoumkh                     continue;
186c2481452Shoumkh                 }
187ef9f9732Shoumkh 
188c2481452Shoumkh                 for e2 in (exp + 1..e + 1).rev() {
189ef9f9732Shoumkh                     if e2 == e {
190ef9f9732Shoumkh                         match self.pop_block(pop_list) {
191ef9f9732Shoumkh                             Ok(region) => {
192ef9f9732Shoumkh                                 if e2 != exp + 1 {
193ef9f9732Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
194ef9f9732Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
195b5b571e0SLoGin                                         &mut self.free_regions[exp2index(e2 - 1)].lock();
196ef9f9732Shoumkh                                     self.split_block(region, e2, low_list_guard);
197ef9f9732Shoumkh                                 } else {
198ef9f9732Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
199ef9f9732Shoumkh                                     // 所以直接将list_guard传入
200ef9f9732Shoumkh                                     self.split_block(region, e2, list_guard);
201ef9f9732Shoumkh                                 }
202ef9f9732Shoumkh                             }
203ef9f9732Shoumkh                             Err(err) => {
204*2eab6dd7S曾俊                                 debug!("buddy_pop_region get wrong");
205ef9f9732Shoumkh                                 return Err(err);
206ef9f9732Shoumkh                             }
207ef9f9732Shoumkh                         }
208ef9f9732Shoumkh                     } else {
209b5b571e0SLoGin                         match self.pop_block(&mut self.free_regions[exp2index(e2)].lock()) {
210c2481452Shoumkh                             Ok(region) => {
211c2481452Shoumkh                                 if e2 != exp + 1 {
212c2481452Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
213c2481452Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
214b5b571e0SLoGin                                         &mut self.free_regions[exp2index(e2 - 1)].lock();
215a7eb62a4Shoumkh                                     self.split_block(region, e2, low_list_guard);
216c2481452Shoumkh                                 } else {
217c2481452Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
218c2481452Shoumkh                                     // 所以直接将list_guard传入
219a7eb62a4Shoumkh                                     self.split_block(region, e2, list_guard);
220c2481452Shoumkh                                 }
221c2481452Shoumkh                             }
222c2481452Shoumkh                             Err(err) => {
223*2eab6dd7S曾俊                                 debug!("buddy_pop_region get wrong");
224c2481452Shoumkh                                 return Err(err);
225c2481452Shoumkh                             }
226c2481452Shoumkh                         }
227c2481452Shoumkh                     }
228ef9f9732Shoumkh                 }
229c2481452Shoumkh                 break;
230c2481452Shoumkh             }
231c2481452Shoumkh             // 判断是否获得了exp大小的内存块
232c2481452Shoumkh             if list_guard.num_free > 0 {
233ef9f9732Shoumkh                 match self.pop_block(list_guard) {
234ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
235ef9f9732Shoumkh                     Err(err) => return Err(err),
236ef9f9732Shoumkh                 }
237c2481452Shoumkh             }
238c2481452Shoumkh             // 拆分大内存块无法获得exp大小内存块
239c2481452Shoumkh             // 尝试用小内存块合成
240c2481452Shoumkh             // 即将两块exp合成一块exp+1
241ef9f9732Shoumkh 
242ef9f9732Shoumkh             // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
243ef9f9732Shoumkh             // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
244ef9f9732Shoumkh             //     if let Err(err) = self.merge_all_exp(
245ef9f9732Shoumkh             //         exp,
246ef9f9732Shoumkh             //         &mut self.free_regions[exp2index(exp) as usize].lock(),
247ef9f9732Shoumkh             //         high_list_guard,
248ef9f9732Shoumkh             //     ) {
249ef9f9732Shoumkh             //         return err;
250ef9f9732Shoumkh             //     } else {
251ef9f9732Shoumkh             //         return MmioResult::SUCCESS;
252ef9f9732Shoumkh             //     }
253ef9f9732Shoumkh             // };
254c2481452Shoumkh             for e in MMIO_BUDDY_MIN_EXP..exp {
255c2481452Shoumkh                 if e != exp - 1 {
256a7eb62a4Shoumkh                     match self.merge_all_exp(
257ef9f9732Shoumkh                         exp,
258b5b571e0SLoGin                         &mut self.free_regions[exp2index(exp)].lock(),
259ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp + 1)].lock(),
260c2481452Shoumkh                     ) {
261c2481452Shoumkh                         Ok(_) => continue,
262c2481452Shoumkh                         Err(err) => {
263*2eab6dd7S曾俊                             debug!("merge_all_exp get wrong");
264c2481452Shoumkh                             return Err(err);
265c2481452Shoumkh                         }
266c2481452Shoumkh                     }
267c2481452Shoumkh                 } else {
268a7eb62a4Shoumkh                     match self.merge_all_exp(
269ef9f9732Shoumkh                         exp,
270b5b571e0SLoGin                         &mut self.free_regions[exp2index(exp)].lock(),
271c2481452Shoumkh                         list_guard,
272c2481452Shoumkh                     ) {
273c2481452Shoumkh                         Ok(_) => continue,
274c2481452Shoumkh                         Err(err) => {
275*2eab6dd7S曾俊                             debug!("merge_all_exp get wrong");
276c2481452Shoumkh                             return Err(err);
277c2481452Shoumkh                         }
278c2481452Shoumkh                     }
279c2481452Shoumkh                 }
280c2481452Shoumkh             }
281c2481452Shoumkh 
282c2481452Shoumkh             //判断是否获得了exp大小的内存块
283c2481452Shoumkh             if list_guard.num_free > 0 {
284ef9f9732Shoumkh                 match self.pop_block(list_guard) {
285ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
286ef9f9732Shoumkh                     Err(err) => return Err(err),
287ef9f9732Shoumkh                 }
288c2481452Shoumkh             }
289c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
290c2481452Shoumkh         } else {
291ef9f9732Shoumkh             match self.pop_block(list_guard) {
292ef9f9732Shoumkh                 Ok(ret) => return Ok(ret),
293ef9f9732Shoumkh                 Err(err) => return Err(err),
294ef9f9732Shoumkh             }
295c2481452Shoumkh         }
296c2481452Shoumkh     }
297c2481452Shoumkh 
298c2481452Shoumkh     /// @brief 对query_addr_region进行封装
299c2481452Shoumkh     ///
300c2481452Shoumkh     /// @param exp 内存区域的大小(2^exp)
301c2481452Shoumkh     ///
30240fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
303c2481452Shoumkh     /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
30440fe15e0SLoGin     fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
30523ef2b33SLoGin         let mut list_guard: SpinLockGuard<MmioFreeRegionList> =
30623ef2b33SLoGin             self.free_regions[exp2index(exp)].lock();
30723ef2b33SLoGin         match self.query_addr_region(exp, &mut list_guard) {
308c2481452Shoumkh             Ok(ret) => return Ok(ret),
309c2481452Shoumkh             Err(err) => {
310*2eab6dd7S曾俊                 debug!("mmio_buddy_query_addr_region failed");
311c2481452Shoumkh                 return Err(err);
312c2481452Shoumkh             }
313c2481452Shoumkh         }
314c2481452Shoumkh     }
315c2481452Shoumkh     /// @brief 往指定的地址空间链表中添加一个地址区域
316c2481452Shoumkh     ///
317c2481452Shoumkh     /// @param region 要被添加的地址结构体
318c2481452Shoumkh     ///
319c2481452Shoumkh     /// @param list_guard 目标链表
320a7eb62a4Shoumkh     fn push_block(
321c2481452Shoumkh         &self,
32240fe15e0SLoGin         region: MmioBuddyAddrRegion,
323c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
324c2481452Shoumkh     ) {
325c2481452Shoumkh         list_guard.list.push_back(region);
326c2481452Shoumkh         list_guard.num_free += 1;
327c2481452Shoumkh     }
328c2481452Shoumkh 
329c2481452Shoumkh     /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
330c2481452Shoumkh     #[inline(always)]
33140fe15e0SLoGin     fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
33240fe15e0SLoGin         return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
333c2481452Shoumkh     }
334c2481452Shoumkh 
335c2481452Shoumkh     /// @brief 寻找并弹出指定内存块的伙伴块
336c2481452Shoumkh     ///
337c2481452Shoumkh     /// @param region 对应内存块的信息
338c2481452Shoumkh     ///
339c2481452Shoumkh     /// @param exp 内存块大小
340c2481452Shoumkh     ///
341c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
342c2481452Shoumkh     ///
343c2481452Shoumkh     /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
344c2481452Shoumkh     /// @return Err(MmioResult)
345c2481452Shoumkh     /// - 当链表为空,返回ISEMPTY
346c2481452Shoumkh     /// - 没有找到伙伴块,返回ENOFOUND
347a7eb62a4Shoumkh     fn pop_buddy_block(
348c2481452Shoumkh         &self,
34940fe15e0SLoGin         vaddr: VirtAddr,
350c2481452Shoumkh         exp: u32,
351c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
35240fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
353b5b571e0SLoGin         if list_guard.list.is_empty() {
354c2481452Shoumkh             return Err(MmioResult::ISEMPTY);
355c2481452Shoumkh         } else {
356c2481452Shoumkh             //计算伙伴块的地址
357a7eb62a4Shoumkh             let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
358c2481452Shoumkh 
359c2481452Shoumkh             // element 只会有一个元素
36040fe15e0SLoGin             let mut element: Vec<MmioBuddyAddrRegion> = list_guard
361c2481452Shoumkh                 .list
3621a72a751SLoGin                 .extract_if(|x| x.vaddr == buddy_vaddr)
363c2481452Shoumkh                 .collect();
364c2481452Shoumkh             if element.len() == 1 {
365c2481452Shoumkh                 list_guard.num_free -= 1;
366c2481452Shoumkh                 return Ok(element.pop().unwrap());
367c2481452Shoumkh             }
368c2481452Shoumkh 
369c2481452Shoumkh             //没有找到对应的伙伴块
370c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
371c2481452Shoumkh         }
372c2481452Shoumkh     }
373c2481452Shoumkh 
374c2481452Shoumkh     /// @brief 从指定空闲链表中取出内存区域
375c2481452Shoumkh     ///
376c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
377c2481452Shoumkh     ///
37840fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
379c2481452Shoumkh     ///
380c2481452Shoumkh     /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
381a7eb62a4Shoumkh     fn pop_block(
382c2481452Shoumkh         &self,
383c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
38440fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
385c2481452Shoumkh         if !list_guard.list.is_empty() {
386c2481452Shoumkh             list_guard.num_free -= 1;
387c2481452Shoumkh             return Ok(list_guard.list.pop_back().unwrap());
388c2481452Shoumkh         }
389c2481452Shoumkh         return Err(MmioResult::ISEMPTY);
390c2481452Shoumkh     }
391c2481452Shoumkh 
392c2481452Shoumkh     /// @brief 合并所有2^{exp}大小的内存块
393c2481452Shoumkh     ///
394c2481452Shoumkh     /// @param exp 内存块大小的幂(2^exp)
395c2481452Shoumkh     ///
396c2481452Shoumkh     /// @param list_guard exp对应的链表
397c2481452Shoumkh     ///
398c2481452Shoumkh     /// @param high_list_guard exp+1对应的链表
399c2481452Shoumkh     ///
400c2481452Shoumkh     /// @return Ok(MmioResult) 合并成功返回SUCCESS
401c2481452Shoumkh     /// @return Err(MmioResult)
402c2481452Shoumkh     /// - 内存块过少,无法合并,返回EINVAL
403a7eb62a4Shoumkh     /// - pop_buddy_block调用出错,返回其错误码
404a7eb62a4Shoumkh     /// - merge_blocks调用出错,返回其错误码
405a7eb62a4Shoumkh     fn merge_all_exp(
406c2481452Shoumkh         &self,
407c2481452Shoumkh         exp: u32,
408c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
409c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
410c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
411c2481452Shoumkh         // 至少要两个内存块才能合并
412c2481452Shoumkh         if list_guard.num_free <= 1 {
413c2481452Shoumkh             return Err(MmioResult::EINVAL);
414c2481452Shoumkh         }
415c2481452Shoumkh         loop {
416c2481452Shoumkh             if list_guard.num_free <= 1 {
417c2481452Shoumkh                 break;
418c2481452Shoumkh             }
419c2481452Shoumkh             // 获取内存块
42040fe15e0SLoGin             let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
421c2481452Shoumkh             // 获取伙伴内存块
422a7eb62a4Shoumkh             match self.pop_buddy_block(vaddr, exp, list_guard) {
423c2481452Shoumkh                 Err(err) => {
424c2481452Shoumkh                     return Err(err);
425c2481452Shoumkh                 }
426c2481452Shoumkh                 Ok(buddy_region) => {
42740fe15e0SLoGin                     let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
42840fe15e0SLoGin                     let copy_region = region.clone();
429c2481452Shoumkh                     // 在两块内存都被取出之后才进行合并
430a7eb62a4Shoumkh                     match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
431c2481452Shoumkh                         Err(err) => {
432c2481452Shoumkh                             // 如果合并失败了要将取出来的元素放回去
433a7eb62a4Shoumkh                             self.push_block(copy_region, list_guard);
434*2eab6dd7S曾俊                             debug!("merge_all_exp: merge_blocks failed");
435c2481452Shoumkh                             return Err(err);
436c2481452Shoumkh                         }
437c2481452Shoumkh                         Ok(_) => continue,
438c2481452Shoumkh                     }
439c2481452Shoumkh                 }
440c2481452Shoumkh             }
441c2481452Shoumkh         }
442c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
443c2481452Shoumkh     }
444c2481452Shoumkh 
445c2481452Shoumkh     /// @brief 合并两个【已经从链表中取出】的内存块
446c2481452Shoumkh     ///
447c2481452Shoumkh     /// @param region_1 第一个内存块
448c2481452Shoumkh     ///
449c2481452Shoumkh     /// @param region_2 第二个内存
450c2481452Shoumkh     ///
451c2481452Shoumkh     /// @return Ok(MmioResult) 成功返回SUCCESS
452c2481452Shoumkh     ///
453c2481452Shoumkh     /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
454a7eb62a4Shoumkh     fn merge_blocks(
455c2481452Shoumkh         &self,
45640fe15e0SLoGin         region_1: MmioBuddyAddrRegion,
45740fe15e0SLoGin         region_2: MmioBuddyAddrRegion,
458c2481452Shoumkh         exp: u32,
459c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
460c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
461c2481452Shoumkh         // 判断是否为伙伴块
462a7eb62a4Shoumkh         if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
463c2481452Shoumkh             return Err(MmioResult::EINVAL);
464c2481452Shoumkh         }
465c2481452Shoumkh         // 将大的块放进下一级链表
466a7eb62a4Shoumkh         self.push_block(region_1, high_list_guard);
467c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
468c2481452Shoumkh     }
469c2481452Shoumkh 
470c2481452Shoumkh     /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
471c2481452Shoumkh     ///
472c2481452Shoumkh     /// @param size mmio区域的大小(字节)
473c2481452Shoumkh     ///
474c2481452Shoumkh     /// @param vm_flags 要把vma设置成的标志
475c2481452Shoumkh     ///
476c2481452Shoumkh     /// @param res_vaddr 返回值-分配得到的虚拟地址
477c2481452Shoumkh     ///
478c2481452Shoumkh     /// @param res_length 返回值-分配的虚拟地址空间长度
479c2481452Shoumkh     ///
480a7eb62a4Shoumkh     /// @return Ok(i32) 成功返回0
481a7eb62a4Shoumkh     ///
482676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
4832dd9f0c7SLoGin     pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
484c2481452Shoumkh         if size > PAGE_1G_SIZE || size == 0 {
485676b8ef6SMork             return Err(SystemError::EPERM);
486c2481452Shoumkh         }
487c2481452Shoumkh         // 计算前导0
4884fda81ceSLoGin         #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
48940fe15e0SLoGin         let mut size_exp: u32 = 63 - size.leading_zeros();
490*2eab6dd7S曾俊         // debug!("create_mmio: size_exp: {}", size_exp);
491c2481452Shoumkh         // 记录最终申请的空间大小
49240fe15e0SLoGin         let mut new_size = size;
493c2481452Shoumkh         // 对齐要申请的空间大小
494c2481452Shoumkh         // 如果要申请的空间大小小于4k,则分配4k
49523ef2b33SLoGin         if size_exp < PAGE_4K_SHIFT as u32 {
496370472f7SLoGin             new_size = PAGE_4K_SIZE;
49723ef2b33SLoGin             size_exp = PAGE_4K_SHIFT as u32;
498c2481452Shoumkh         } else if (new_size & (!(1 << size_exp))) != 0 {
499c2481452Shoumkh             // 向左对齐空间大小
500c2481452Shoumkh             size_exp += 1;
501c2481452Shoumkh             new_size = 1 << size_exp;
502c2481452Shoumkh         }
50340fe15e0SLoGin         match self.mmio_buddy_query_addr_region(size_exp) {
504c2481452Shoumkh             Ok(region) => {
5052dd9f0c7SLoGin                 let space_guard =
5062dd9f0c7SLoGin                     unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) };
5072dd9f0c7SLoGin                 return Ok(space_guard);
508c2481452Shoumkh             }
509c2481452Shoumkh             Err(_) => {
510*2eab6dd7S曾俊                 error!(
5111496ba7bSLoGin                     "failed to create mmio. pid = {:?}",
5121496ba7bSLoGin                     ProcessManager::current_pcb().pid()
5131496ba7bSLoGin                 );
514676b8ef6SMork                 return Err(SystemError::ENOMEM);
515c2481452Shoumkh             }
516c2481452Shoumkh         }
517c2481452Shoumkh     }
518c2481452Shoumkh 
519c2481452Shoumkh     /// @brief 取消mmio的映射并将地址空间归还到buddy中
520c2481452Shoumkh     ///
521c2481452Shoumkh     /// @param vaddr 起始的虚拟地址
522c2481452Shoumkh     ///
523c2481452Shoumkh     /// @param length 要归还的地址空间的长度
524c2481452Shoumkh     ///
525c2481452Shoumkh     /// @return Ok(i32) 成功返回0
526c2481452Shoumkh     ///
527676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
5287eda31b2SLoGin     pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
52940fe15e0SLoGin         assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
53040fe15e0SLoGin         assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
53140fe15e0SLoGin         if vaddr < self.pool_start_addr
53240fe15e0SLoGin             || vaddr.data() >= self.pool_start_addr.data() + self.pool_size
53340fe15e0SLoGin         {
534676b8ef6SMork             return Err(SystemError::EINVAL);
535c2481452Shoumkh         }
53640fe15e0SLoGin         // todo: 重构MMIO管理机制,创建类似全局的manager之类的,管理MMIO的空间?
53740fe15e0SLoGin 
53840fe15e0SLoGin         // 暂时认为传入的vaddr都是正确的
53940fe15e0SLoGin         let page_count = length / MMArch::PAGE_SIZE;
54040fe15e0SLoGin         // 取消映射
54140fe15e0SLoGin         let mut bindings = KernelMapper::lock();
54240fe15e0SLoGin         let mut kernel_mapper = bindings.as_mut();
54340fe15e0SLoGin         if kernel_mapper.is_none() {
544*2eab6dd7S曾俊             warn!("release_mmio: kernel_mapper is read only");
54540fe15e0SLoGin             return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
546c2481452Shoumkh         }
54740fe15e0SLoGin 
54840fe15e0SLoGin         for i in 0..page_count {
549c2481452Shoumkh             unsafe {
5507ae679ddSLoGin                 let x: Option<(
5517ae679ddSLoGin                     PhysAddr,
5527ae679ddSLoGin                     PageFlags<MMArch>,
5537ae679ddSLoGin                     crate::mm::page::PageFlush<MMArch>,
5547ae679ddSLoGin                 )> = kernel_mapper
55540fe15e0SLoGin                     .as_mut()
55640fe15e0SLoGin                     .unwrap()
5577ae679ddSLoGin                     .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, false);
5587ae679ddSLoGin                 if let Some((_, _, flush)) = x {
5597ae679ddSLoGin                     flush.flush();
5607ae679ddSLoGin                 }
56140fe15e0SLoGin             };
562c2481452Shoumkh         }
56340fe15e0SLoGin 
5647ae679ddSLoGin         // 归还到buddy
5657ae679ddSLoGin         mmio_pool()
566b5b571e0SLoGin             .give_back_block(vaddr, length.trailing_zeros())
5677ae679ddSLoGin             .unwrap_or_else(|err| {
5687ae679ddSLoGin                 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
5697ae679ddSLoGin             });
57040fe15e0SLoGin 
571a7eb62a4Shoumkh         return Ok(0);
572a7eb62a4Shoumkh     }
573a7eb62a4Shoumkh }
574a7eb62a4Shoumkh 
575a7eb62a4Shoumkh /// @brief mmio伙伴系统内部的地址区域结构体
57640fe15e0SLoGin #[derive(Debug, Clone)]
57740fe15e0SLoGin struct MmioBuddyAddrRegion {
57840fe15e0SLoGin     vaddr: VirtAddr,
579a7eb62a4Shoumkh }
580a7eb62a4Shoumkh impl MmioBuddyAddrRegion {
58140fe15e0SLoGin     pub fn new(vaddr: VirtAddr) -> Self {
58240fe15e0SLoGin         return MmioBuddyAddrRegion { vaddr };
583a7eb62a4Shoumkh     }
58440fe15e0SLoGin 
58540fe15e0SLoGin     #[allow(dead_code)]
58640fe15e0SLoGin     pub fn vaddr(&self) -> VirtAddr {
58740fe15e0SLoGin         return self.vaddr;
588a7eb62a4Shoumkh     }
589a7eb62a4Shoumkh }
590a7eb62a4Shoumkh 
591a7eb62a4Shoumkh /// @brief 空闲页数组结构体
592b5b571e0SLoGin #[derive(Debug, Default)]
593a7eb62a4Shoumkh pub struct MmioFreeRegionList {
594a7eb62a4Shoumkh     /// 存储mmio_buddy的地址链表
59540fe15e0SLoGin     list: LinkedList<MmioBuddyAddrRegion>,
596a7eb62a4Shoumkh     /// 空闲块的数量
597a7eb62a4Shoumkh     num_free: i64,
598a7eb62a4Shoumkh }
599a7eb62a4Shoumkh impl MmioFreeRegionList {
60064aea4b3SGou Ngai     #[allow(dead_code)]
601a7eb62a4Shoumkh     fn new() -> Self {
602a7eb62a4Shoumkh         return MmioFreeRegionList {
603a7eb62a4Shoumkh             ..Default::default()
604a7eb62a4Shoumkh         };
605a7eb62a4Shoumkh     }
606a7eb62a4Shoumkh }
607a7eb62a4Shoumkh 
608a7eb62a4Shoumkh /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
609a7eb62a4Shoumkh ///
610a7eb62a4Shoumkh /// @param exp内存大小
611a7eb62a4Shoumkh ///
612a7eb62a4Shoumkh /// @return 内存池数组下标
613a7eb62a4Shoumkh #[inline(always)]
614a7eb62a4Shoumkh fn exp2index(exp: u32) -> usize {
615a7eb62a4Shoumkh     return (exp - 12) as usize;
616a7eb62a4Shoumkh }
617a7eb62a4Shoumkh 
6182dd9f0c7SLoGin #[derive(Debug)]
6192dd9f0c7SLoGin pub struct MMIOSpaceGuard {
6202dd9f0c7SLoGin     vaddr: VirtAddr,
6212dd9f0c7SLoGin     size: usize,
6222dd9f0c7SLoGin     mapped: AtomicBool,
6232dd9f0c7SLoGin }
6242dd9f0c7SLoGin 
6252dd9f0c7SLoGin impl MMIOSpaceGuard {
6262dd9f0c7SLoGin     pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self {
6272dd9f0c7SLoGin         // check size
6282dd9f0c7SLoGin         assert!(
6292dd9f0c7SLoGin             size & (MMArch::PAGE_SIZE - 1) == 0,
6302dd9f0c7SLoGin             "MMIO space size must be page aligned"
6312dd9f0c7SLoGin         );
6322dd9f0c7SLoGin         assert!(size.is_power_of_two(), "MMIO space size must be power of 2");
6332dd9f0c7SLoGin         assert!(
6342dd9f0c7SLoGin             vaddr.check_aligned(size),
6352dd9f0c7SLoGin             "MMIO space vaddr must be aligned with size"
6362dd9f0c7SLoGin         );
6372dd9f0c7SLoGin         assert!(
63823ef2b33SLoGin             vaddr.data() >= MMArch::MMIO_BASE.data()
63923ef2b33SLoGin                 && vaddr.data() + size <= MMArch::MMIO_TOP.data(),
6402dd9f0c7SLoGin             "MMIO space must be in MMIO region"
6412dd9f0c7SLoGin         );
6422dd9f0c7SLoGin 
6432dd9f0c7SLoGin         // 人工创建的MMIO空间,认为已经映射
6442dd9f0c7SLoGin         MMIOSpaceGuard {
6452dd9f0c7SLoGin             vaddr,
6462dd9f0c7SLoGin             size,
6472dd9f0c7SLoGin             mapped: AtomicBool::new(mapped),
6482dd9f0c7SLoGin         }
6492dd9f0c7SLoGin     }
6502dd9f0c7SLoGin 
6512dd9f0c7SLoGin     pub fn vaddr(&self) -> VirtAddr {
6522dd9f0c7SLoGin         self.vaddr
6532dd9f0c7SLoGin     }
6542dd9f0c7SLoGin 
6552dd9f0c7SLoGin     pub fn size(&self) -> usize {
6562dd9f0c7SLoGin         self.size
6572dd9f0c7SLoGin     }
6582dd9f0c7SLoGin 
6592dd9f0c7SLoGin     /// 将物理地址填写到虚拟地址空间中
6602dd9f0c7SLoGin     ///
6612dd9f0c7SLoGin     /// ## Safety
6622dd9f0c7SLoGin     ///
6632dd9f0c7SLoGin     /// 传入的物理地址【一定要是设备的物理地址】。
6642dd9f0c7SLoGin     /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
6657ae679ddSLoGin     pub unsafe fn map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError> {
6662dd9f0c7SLoGin         if length > self.size {
6677ae679ddSLoGin             return Err(SystemError::EINVAL);
6682dd9f0c7SLoGin         }
6692dd9f0c7SLoGin 
6702dd9f0c7SLoGin         let check = self
6712dd9f0c7SLoGin             .mapped
6722dd9f0c7SLoGin             .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
6732dd9f0c7SLoGin         if check.is_err() {
6747ae679ddSLoGin             return Err(SystemError::EINVAL);
6752dd9f0c7SLoGin         }
6762dd9f0c7SLoGin 
6772dd9f0c7SLoGin         let flags = PageFlags::mmio_flags();
678731bc2b3SLoGin 
6792dd9f0c7SLoGin         let mut kernel_mapper = KernelMapper::lock();
6802dd9f0c7SLoGin         let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
6817ae679ddSLoGin         return r;
6822dd9f0c7SLoGin     }
6837ae679ddSLoGin 
6840102d69fSLoGin     /// # map_any_phys - 将任意物理地址映射到虚拟地址
6850102d69fSLoGin     ///
6860102d69fSLoGin     /// 将指定的物理地址和长度映射到虚拟地址空间。
6870102d69fSLoGin     ///
6880102d69fSLoGin     /// ## 参数
6890102d69fSLoGin     ///
6900102d69fSLoGin     /// - `paddr`: 物理地址,需要被映射的起始地址。
6910102d69fSLoGin     /// - `length`: 要映射的物理地址长度。
6920102d69fSLoGin     ///
6930102d69fSLoGin     /// ## 返回值
6940102d69fSLoGin     /// - `Ok(VirtAddr)`: 映射成功,返回虚拟地址的起始地址。
6950102d69fSLoGin     /// - `Err(SystemError)`: 映射失败,返回系统错误。
6960102d69fSLoGin     ///
6970102d69fSLoGin     /// ## 副作用
6980102d69fSLoGin     ///
6990102d69fSLoGin     /// 该函数会修改虚拟地址空间,将物理地址映射到虚拟地址。
7000102d69fSLoGin     ///
7010102d69fSLoGin     /// ## Safety
7020102d69fSLoGin     ///
7030102d69fSLoGin     /// 由于该函数涉及到内存操作,因此它是非安全的。确保在调用该函数时,你传入的物理地址是正确的。
7040102d69fSLoGin     #[allow(dead_code)]
7050102d69fSLoGin     pub unsafe fn map_any_phys(
7060102d69fSLoGin         &self,
7070102d69fSLoGin         paddr: PhysAddr,
7080102d69fSLoGin         length: usize,
7090102d69fSLoGin     ) -> Result<VirtAddr, SystemError> {
7100102d69fSLoGin         let paddr_base = PhysAddr::new(page_align_down(paddr.data()));
7110102d69fSLoGin         let offset = paddr - paddr_base;
7120102d69fSLoGin         let vaddr_base = self.vaddr;
7130102d69fSLoGin         let vaddr = vaddr_base + offset;
7140102d69fSLoGin 
7150102d69fSLoGin         self.map_phys(paddr_base, page_align_up(length + offset))?;
7160102d69fSLoGin         return Ok(vaddr);
7170102d69fSLoGin     }
7180102d69fSLoGin 
7197ae679ddSLoGin     /// 泄露一个MMIO space guard,不会释放映射的空间
7207ae679ddSLoGin     pub unsafe fn leak(self) {
7217ae679ddSLoGin         core::mem::forget(self);
7222dd9f0c7SLoGin     }
7232dd9f0c7SLoGin }
7242dd9f0c7SLoGin 
7252dd9f0c7SLoGin impl Drop for MMIOSpaceGuard {
7262dd9f0c7SLoGin     fn drop(&mut self) {
7272dd9f0c7SLoGin         let _ = mmio_pool()
7282dd9f0c7SLoGin             .release_mmio(self.vaddr, self.size)
7292dd9f0c7SLoGin             .unwrap_or_else(|err| {
7302dd9f0c7SLoGin                 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
7312dd9f0c7SLoGin             });
7322dd9f0c7SLoGin     }
7332dd9f0c7SLoGin }
7342dd9f0c7SLoGin 
73540fe15e0SLoGin pub fn mmio_init() {
736*2eab6dd7S曾俊     debug!("Initializing MMIO buddy memory pool...");
73740fe15e0SLoGin     // 初始化mmio内存池
73840fe15e0SLoGin     unsafe {
73940fe15e0SLoGin         __MMIO_POOL = Some(MmioBuddyMemPool::new());
74040fe15e0SLoGin     }
74140fe15e0SLoGin 
742*2eab6dd7S曾俊     info!("MMIO buddy memory pool init done");
74340fe15e0SLoGin }
744