xref: /DragonOS/kernel/src/mm/mmio_buddy.rs (revision 40fe15e0953f989ccfeb74826d61621d43dea6bb)
1a7eb62a4Shoumkh use crate::libs::spinlock::{SpinLock, SpinLockGuard};
2*40fe15e0SLoGin use crate::mm::kernel_mapper::KernelMapper;
3676b8ef6SMork use crate::syscall::SystemError;
4c2481452Shoumkh use crate::{
5c2481452Shoumkh     arch::asm::current::current_pcb,
6*40fe15e0SLoGin     include::bindings::bindings::{vm_flags_t, PAGE_1G_SHIFT, PAGE_4K_SHIFT, PAGE_4K_SIZE},
7*40fe15e0SLoGin     kdebug,
8*40fe15e0SLoGin     mm::{MMArch, MemoryManagementArch},
9c2481452Shoumkh };
10*40fe15e0SLoGin use crate::{kerror, kinfo, kwarn};
11*40fe15e0SLoGin use alloc::{collections::LinkedList, vec::Vec};
12*40fe15e0SLoGin use core::mem;
13*40fe15e0SLoGin use core::mem::MaybeUninit;
14*40fe15e0SLoGin use core::sync::atomic::{compiler_fence, Ordering};
15*40fe15e0SLoGin 
16*40fe15e0SLoGin use super::VirtAddr;
17c2481452Shoumkh 
18c2481452Shoumkh // 最大的伙伴块的幂
19c2481452Shoumkh const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT;
20c2481452Shoumkh // 最小的伙伴块的幂
21c2481452Shoumkh const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT;
22c2481452Shoumkh // 内存池数组的范围
23c2481452Shoumkh const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
24c2481452Shoumkh 
25*40fe15e0SLoGin const MMIO_BASE: VirtAddr = VirtAddr::new(0xffffa10000000000);
26*40fe15e0SLoGin const MMIO_TOP: VirtAddr = VirtAddr::new(0xffffa20000000000);
27*40fe15e0SLoGin 
28*40fe15e0SLoGin const PAGE_1G_SIZE: usize = 1 << 30;
29*40fe15e0SLoGin 
30*40fe15e0SLoGin static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
31*40fe15e0SLoGin 
32*40fe15e0SLoGin pub fn mmio_pool() -> &'static mut MmioBuddyMemPool {
33*40fe15e0SLoGin     unsafe { __MMIO_POOL.as_mut().unwrap() }
34c2481452Shoumkh }
35c2481452Shoumkh 
36c2481452Shoumkh pub enum MmioResult {
37c2481452Shoumkh     SUCCESS,
38c2481452Shoumkh     EINVAL,
39c2481452Shoumkh     ENOFOUND,
40c2481452Shoumkh     WRONGEXP,
41c2481452Shoumkh     ISEMPTY,
42c2481452Shoumkh }
43c2481452Shoumkh 
44c2481452Shoumkh /// @brief buddy内存池
45*40fe15e0SLoGin #[derive(Debug)]
46c2481452Shoumkh pub struct MmioBuddyMemPool {
47*40fe15e0SLoGin     pool_start_addr: VirtAddr,
48*40fe15e0SLoGin     pool_size: usize,
49c2481452Shoumkh     free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
50c2481452Shoumkh }
51*40fe15e0SLoGin 
52c2481452Shoumkh impl MmioBuddyMemPool {
53c2481452Shoumkh     fn new() -> Self {
54*40fe15e0SLoGin         let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
55*40fe15e0SLoGin             MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
56*40fe15e0SLoGin         for i in 0..MMIO_BUDDY_REGION_COUNT {
57*40fe15e0SLoGin             free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
58*40fe15e0SLoGin         }
59*40fe15e0SLoGin         let free_regions = unsafe {
60*40fe15e0SLoGin             mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
61*40fe15e0SLoGin                 free_regions,
62*40fe15e0SLoGin             )
63c2481452Shoumkh         };
64*40fe15e0SLoGin 
65*40fe15e0SLoGin         let pool = MmioBuddyMemPool {
66*40fe15e0SLoGin             pool_start_addr: MMIO_BASE,
67*40fe15e0SLoGin             pool_size: MMIO_TOP - MMIO_BASE,
68*40fe15e0SLoGin             free_regions,
69*40fe15e0SLoGin         };
70*40fe15e0SLoGin         kdebug!("MMIO buddy pool init: created");
71*40fe15e0SLoGin 
72*40fe15e0SLoGin         let cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) >> 30;
73*40fe15e0SLoGin         let mut vaddr_base = MMIO_BASE;
74*40fe15e0SLoGin         kdebug!("total 1G blocks: {cnt_1g_blocks}");
75*40fe15e0SLoGin         for _i in 0..cnt_1g_blocks {
76*40fe15e0SLoGin             compiler_fence(Ordering::SeqCst);
77*40fe15e0SLoGin             match pool.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
78*40fe15e0SLoGin                 Ok(_) => {
79*40fe15e0SLoGin                     vaddr_base += PAGE_1G_SIZE;
80*40fe15e0SLoGin                 }
81*40fe15e0SLoGin                 Err(_) => {
82*40fe15e0SLoGin                     panic!("MMIO buddy pool init failed");
83*40fe15e0SLoGin                 }
84*40fe15e0SLoGin             }
85*40fe15e0SLoGin         }
86*40fe15e0SLoGin         kdebug!("MMIO buddy pool init success");
87*40fe15e0SLoGin         return pool;
88c2481452Shoumkh     }
89c2481452Shoumkh 
90c2481452Shoumkh     /// @brief 创建新的地址区域结构体
91c2481452Shoumkh     ///
92c2481452Shoumkh     /// @param vaddr 虚拟地址
93c2481452Shoumkh     ///
94c2481452Shoumkh     /// @return 创建好的地址区域结构体
95*40fe15e0SLoGin     fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
96*40fe15e0SLoGin         // kdebug!("create_region for vaddr: {vaddr:?}");
97*40fe15e0SLoGin 
98*40fe15e0SLoGin         let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
99*40fe15e0SLoGin 
100*40fe15e0SLoGin         // kdebug!("create_region for vaddr: {vaddr:?} OK!!!");
101c2481452Shoumkh         return region;
102c2481452Shoumkh     }
103c2481452Shoumkh 
104c2481452Shoumkh     /// @brief 将内存块归还给buddy
105c2481452Shoumkh     ///
106c2481452Shoumkh     /// @param vaddr 虚拟地址
107c2481452Shoumkh     ///
108c2481452Shoumkh     /// @param exp 内存空间的大小(2^exp)
109c2481452Shoumkh     ///
110c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
111c2481452Shoumkh     ///
112c2481452Shoumkh     /// @return Ok(i32) 返回0
113c2481452Shoumkh     ///
114676b8ef6SMork     /// @return Err(SystemError) 返回错误码
115*40fe15e0SLoGin     fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
116c2481452Shoumkh         // 确保内存对齐,低位都要为0
117*40fe15e0SLoGin         if (vaddr.data() & ((1 << exp) - 1)) != 0 {
118676b8ef6SMork             return Err(SystemError::EINVAL);
119c2481452Shoumkh         }
120*40fe15e0SLoGin         let region: MmioBuddyAddrRegion = self.create_region(vaddr);
121c2481452Shoumkh         // 加入buddy
122*40fe15e0SLoGin         let mut list_guard = self.free_regions[exp2index(exp)].lock();
123*40fe15e0SLoGin 
124*40fe15e0SLoGin         self.push_block(region, &mut list_guard);
125c2481452Shoumkh         return Ok(0);
126c2481452Shoumkh     }
127c2481452Shoumkh 
128c2481452Shoumkh     /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中
129c2481452Shoumkh     ///
130c2481452Shoumkh     /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
131c2481452Shoumkh     ///
132c2481452Shoumkh     /// @param exp 要被分割的地址区域的大小的幂
133c2481452Shoumkh     ///
134c2481452Shoumkh     /// @param list_guard 【exp-1】对应的链表
135a7eb62a4Shoumkh     fn split_block(
136c2481452Shoumkh         &self,
137*40fe15e0SLoGin         region: MmioBuddyAddrRegion,
138c2481452Shoumkh         exp: u32,
139c2481452Shoumkh         low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
140c2481452Shoumkh     ) {
141*40fe15e0SLoGin         let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
142*40fe15e0SLoGin         let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
143a7eb62a4Shoumkh         self.push_block(region, low_list_guard);
144a7eb62a4Shoumkh         self.push_block(new_region, low_list_guard);
145c2481452Shoumkh     }
146c2481452Shoumkh 
147c2481452Shoumkh     /// @brief 从buddy中申请一块指定大小的内存区域
148c2481452Shoumkh     ///
149c2481452Shoumkh     /// @param exp 要申请的内存块的大小的幂(2^exp)
150c2481452Shoumkh     ///
151c2481452Shoumkh     /// @param list_guard exp对应的链表
152c2481452Shoumkh     ///
153*40fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
154c2481452Shoumkh     ///
155c2481452Shoumkh     /// @return Err(MmioResult)
156c2481452Shoumkh     /// - 没有满足要求的内存块时,返回ENOFOUND
157c2481452Shoumkh     /// - 申请的内存块大小超过合法范围,返回WRONGEXP
158c2481452Shoumkh     /// - 调用函数出错时,返回出错函数对应错误码
159a7eb62a4Shoumkh     fn query_addr_region(
160c2481452Shoumkh         &self,
161c2481452Shoumkh         exp: u32,
162c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
163*40fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
164c2481452Shoumkh         // 申请范围错误
165c2481452Shoumkh         if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP {
166a7eb62a4Shoumkh             kdebug!("query_addr_region: exp wrong");
167c2481452Shoumkh             return Err(MmioResult::WRONGEXP);
168c2481452Shoumkh         }
169c2481452Shoumkh         // 没有恰好符合要求的内存块
170c2481452Shoumkh         // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】
171c2481452Shoumkh         if list_guard.num_free == 0 {
172c2481452Shoumkh             // 找到最小符合申请范围的内存块
173c2481452Shoumkh             // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp
174c2481452Shoumkh             for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
175ef9f9732Shoumkh                 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
176ef9f9732Shoumkh                     &mut self.free_regions[exp2index(e) as usize].lock();
177ef9f9732Shoumkh                 if pop_list.num_free == 0 {
178c2481452Shoumkh                     continue;
179c2481452Shoumkh                 }
180ef9f9732Shoumkh 
181c2481452Shoumkh                 for e2 in (exp + 1..e + 1).rev() {
182ef9f9732Shoumkh                     if e2 == e {
183ef9f9732Shoumkh                         match self.pop_block(pop_list) {
184ef9f9732Shoumkh                             Ok(region) => {
185ef9f9732Shoumkh                                 if e2 != exp + 1 {
186ef9f9732Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
187ef9f9732Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
188ef9f9732Shoumkh                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
189ef9f9732Shoumkh                                     self.split_block(region, e2, low_list_guard);
190ef9f9732Shoumkh                                 } else {
191ef9f9732Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
192ef9f9732Shoumkh                                     // 所以直接将list_guard传入
193ef9f9732Shoumkh                                     self.split_block(region, e2, list_guard);
194ef9f9732Shoumkh                                 }
195ef9f9732Shoumkh                             }
196ef9f9732Shoumkh                             Err(err) => {
197ef9f9732Shoumkh                                 kdebug!("buddy_pop_region get wrong");
198ef9f9732Shoumkh                                 return Err(err);
199ef9f9732Shoumkh                             }
200ef9f9732Shoumkh                         }
201ef9f9732Shoumkh                     } else {
202ef9f9732Shoumkh                         match self.pop_block(&mut self.free_regions[exp2index(e2) as usize].lock())
203ef9f9732Shoumkh                         {
204c2481452Shoumkh                             Ok(region) => {
205c2481452Shoumkh                                 if e2 != exp + 1 {
206c2481452Shoumkh                                     // 要将分裂后的内存块插入到更小的链表中
207c2481452Shoumkh                                     let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
208a7eb62a4Shoumkh                                         &mut self.free_regions[exp2index(e2 - 1) as usize].lock();
209a7eb62a4Shoumkh                                     self.split_block(region, e2, low_list_guard);
210c2481452Shoumkh                                 } else {
211c2481452Shoumkh                                     // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
212c2481452Shoumkh                                     // 所以直接将list_guard传入
213a7eb62a4Shoumkh                                     self.split_block(region, e2, list_guard);
214c2481452Shoumkh                                 }
215c2481452Shoumkh                             }
216c2481452Shoumkh                             Err(err) => {
217c2481452Shoumkh                                 kdebug!("buddy_pop_region get wrong");
218c2481452Shoumkh                                 return Err(err);
219c2481452Shoumkh                             }
220c2481452Shoumkh                         }
221c2481452Shoumkh                     }
222ef9f9732Shoumkh                 }
223c2481452Shoumkh                 break;
224c2481452Shoumkh             }
225c2481452Shoumkh             // 判断是否获得了exp大小的内存块
226c2481452Shoumkh             if list_guard.num_free > 0 {
227ef9f9732Shoumkh                 match self.pop_block(list_guard) {
228ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
229ef9f9732Shoumkh                     Err(err) => return Err(err),
230ef9f9732Shoumkh                 }
231c2481452Shoumkh             }
232c2481452Shoumkh             // 拆分大内存块无法获得exp大小内存块
233c2481452Shoumkh             // 尝试用小内存块合成
234c2481452Shoumkh             // 即将两块exp合成一块exp+1
235ef9f9732Shoumkh 
236ef9f9732Shoumkh             // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
237ef9f9732Shoumkh             // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
238ef9f9732Shoumkh             //     if let Err(err) = self.merge_all_exp(
239ef9f9732Shoumkh             //         exp,
240ef9f9732Shoumkh             //         &mut self.free_regions[exp2index(exp) as usize].lock(),
241ef9f9732Shoumkh             //         high_list_guard,
242ef9f9732Shoumkh             //     ) {
243ef9f9732Shoumkh             //         return err;
244ef9f9732Shoumkh             //     } else {
245ef9f9732Shoumkh             //         return MmioResult::SUCCESS;
246ef9f9732Shoumkh             //     }
247ef9f9732Shoumkh             // };
248c2481452Shoumkh             for e in MMIO_BUDDY_MIN_EXP..exp {
249c2481452Shoumkh                 if e != exp - 1 {
250a7eb62a4Shoumkh                     match self.merge_all_exp(
251ef9f9732Shoumkh                         exp,
252ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp) as usize].lock(),
253ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp + 1)].lock(),
254c2481452Shoumkh                     ) {
255c2481452Shoumkh                         Ok(_) => continue,
256c2481452Shoumkh                         Err(err) => {
257ef9f9732Shoumkh                             kdebug!("merge_all_exp get wrong");
258c2481452Shoumkh                             return Err(err);
259c2481452Shoumkh                         }
260c2481452Shoumkh                     }
261c2481452Shoumkh                 } else {
262a7eb62a4Shoumkh                     match self.merge_all_exp(
263ef9f9732Shoumkh                         exp,
264ef9f9732Shoumkh                         &mut self.free_regions[exp2index(exp) as usize].lock(),
265c2481452Shoumkh                         list_guard,
266c2481452Shoumkh                     ) {
267c2481452Shoumkh                         Ok(_) => continue,
268c2481452Shoumkh                         Err(err) => {
269ef9f9732Shoumkh                             kdebug!("merge_all_exp get wrong");
270c2481452Shoumkh                             return Err(err);
271c2481452Shoumkh                         }
272c2481452Shoumkh                     }
273c2481452Shoumkh                 }
274c2481452Shoumkh             }
275c2481452Shoumkh 
276c2481452Shoumkh             //判断是否获得了exp大小的内存块
277c2481452Shoumkh             if list_guard.num_free > 0 {
278ef9f9732Shoumkh                 match self.pop_block(list_guard) {
279ef9f9732Shoumkh                     Ok(ret) => return Ok(ret),
280ef9f9732Shoumkh                     Err(err) => return Err(err),
281ef9f9732Shoumkh                 }
282c2481452Shoumkh             }
283c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
284c2481452Shoumkh         } else {
285ef9f9732Shoumkh             match self.pop_block(list_guard) {
286ef9f9732Shoumkh                 Ok(ret) => return Ok(ret),
287ef9f9732Shoumkh                 Err(err) => return Err(err),
288ef9f9732Shoumkh             }
289c2481452Shoumkh         }
290c2481452Shoumkh     }
291c2481452Shoumkh 
292c2481452Shoumkh     /// @brief 对query_addr_region进行封装
293c2481452Shoumkh     ///
294c2481452Shoumkh     /// @param exp 内存区域的大小(2^exp)
295c2481452Shoumkh     ///
296*40fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
297c2481452Shoumkh     /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
298*40fe15e0SLoGin     fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
299c2481452Shoumkh         let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
300a7eb62a4Shoumkh             &mut self.free_regions[exp2index(exp)].lock();
301a7eb62a4Shoumkh         match self.query_addr_region(exp, list_guard) {
302c2481452Shoumkh             Ok(ret) => return Ok(ret),
303c2481452Shoumkh             Err(err) => {
304c2481452Shoumkh                 kdebug!("mmio_buddy_query_addr_region failed");
305c2481452Shoumkh                 return Err(err);
306c2481452Shoumkh             }
307c2481452Shoumkh         }
308c2481452Shoumkh     }
309c2481452Shoumkh     /// @brief 往指定的地址空间链表中添加一个地址区域
310c2481452Shoumkh     ///
311c2481452Shoumkh     /// @param region 要被添加的地址结构体
312c2481452Shoumkh     ///
313c2481452Shoumkh     /// @param list_guard 目标链表
314a7eb62a4Shoumkh     fn push_block(
315c2481452Shoumkh         &self,
316*40fe15e0SLoGin         region: MmioBuddyAddrRegion,
317c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
318c2481452Shoumkh     ) {
319c2481452Shoumkh         list_guard.list.push_back(region);
320c2481452Shoumkh         list_guard.num_free += 1;
321c2481452Shoumkh     }
322c2481452Shoumkh 
323c2481452Shoumkh     /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
324c2481452Shoumkh     #[inline(always)]
325*40fe15e0SLoGin     fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
326*40fe15e0SLoGin         return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
327c2481452Shoumkh     }
328c2481452Shoumkh 
329c2481452Shoumkh     /// @brief 寻找并弹出指定内存块的伙伴块
330c2481452Shoumkh     ///
331c2481452Shoumkh     /// @param region 对应内存块的信息
332c2481452Shoumkh     ///
333c2481452Shoumkh     /// @param exp 内存块大小
334c2481452Shoumkh     ///
335c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
336c2481452Shoumkh     ///
337c2481452Shoumkh     /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
338c2481452Shoumkh     /// @return Err(MmioResult)
339c2481452Shoumkh     /// - 当链表为空,返回ISEMPTY
340c2481452Shoumkh     /// - 没有找到伙伴块,返回ENOFOUND
341a7eb62a4Shoumkh     fn pop_buddy_block(
342c2481452Shoumkh         &self,
343*40fe15e0SLoGin         vaddr: VirtAddr,
344c2481452Shoumkh         exp: u32,
345c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
346*40fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
347c2481452Shoumkh         if list_guard.list.len() == 0 {
348c2481452Shoumkh             return Err(MmioResult::ISEMPTY);
349c2481452Shoumkh         } else {
350c2481452Shoumkh             //计算伙伴块的地址
351a7eb62a4Shoumkh             let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
352c2481452Shoumkh 
353c2481452Shoumkh             // element 只会有一个元素
354*40fe15e0SLoGin             let mut element: Vec<MmioBuddyAddrRegion> = list_guard
355c2481452Shoumkh                 .list
356c2481452Shoumkh                 .drain_filter(|x| x.vaddr == buddy_vaddr)
357c2481452Shoumkh                 .collect();
358c2481452Shoumkh             if element.len() == 1 {
359c2481452Shoumkh                 list_guard.num_free -= 1;
360c2481452Shoumkh                 return Ok(element.pop().unwrap());
361c2481452Shoumkh             }
362c2481452Shoumkh 
363c2481452Shoumkh             //没有找到对应的伙伴块
364c2481452Shoumkh             return Err(MmioResult::ENOFOUND);
365c2481452Shoumkh         }
366c2481452Shoumkh     }
367c2481452Shoumkh 
368c2481452Shoumkh     /// @brief 从指定空闲链表中取出内存区域
369c2481452Shoumkh     ///
370c2481452Shoumkh     /// @param list_guard 【exp】对应的链表
371c2481452Shoumkh     ///
372*40fe15e0SLoGin     /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
373c2481452Shoumkh     ///
374c2481452Shoumkh     /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
375a7eb62a4Shoumkh     fn pop_block(
376c2481452Shoumkh         &self,
377c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
378*40fe15e0SLoGin     ) -> Result<MmioBuddyAddrRegion, MmioResult> {
379c2481452Shoumkh         if !list_guard.list.is_empty() {
380c2481452Shoumkh             list_guard.num_free -= 1;
381c2481452Shoumkh             return Ok(list_guard.list.pop_back().unwrap());
382c2481452Shoumkh         }
383c2481452Shoumkh         return Err(MmioResult::ISEMPTY);
384c2481452Shoumkh     }
385c2481452Shoumkh 
386c2481452Shoumkh     /// @brief 合并所有2^{exp}大小的内存块
387c2481452Shoumkh     ///
388c2481452Shoumkh     /// @param exp 内存块大小的幂(2^exp)
389c2481452Shoumkh     ///
390c2481452Shoumkh     /// @param list_guard exp对应的链表
391c2481452Shoumkh     ///
392c2481452Shoumkh     /// @param high_list_guard exp+1对应的链表
393c2481452Shoumkh     ///
394c2481452Shoumkh     /// @return Ok(MmioResult) 合并成功返回SUCCESS
395c2481452Shoumkh     /// @return Err(MmioResult)
396c2481452Shoumkh     /// - 内存块过少,无法合并,返回EINVAL
397a7eb62a4Shoumkh     /// - pop_buddy_block调用出错,返回其错误码
398a7eb62a4Shoumkh     /// - merge_blocks调用出错,返回其错误码
399a7eb62a4Shoumkh     fn merge_all_exp(
400c2481452Shoumkh         &self,
401c2481452Shoumkh         exp: u32,
402c2481452Shoumkh         list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
403c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
404c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
405c2481452Shoumkh         // 至少要两个内存块才能合并
406c2481452Shoumkh         if list_guard.num_free <= 1 {
407c2481452Shoumkh             return Err(MmioResult::EINVAL);
408c2481452Shoumkh         }
409c2481452Shoumkh         loop {
410c2481452Shoumkh             if list_guard.num_free <= 1 {
411c2481452Shoumkh                 break;
412c2481452Shoumkh             }
413c2481452Shoumkh             // 获取内存块
414*40fe15e0SLoGin             let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
415c2481452Shoumkh             // 获取伙伴内存块
416a7eb62a4Shoumkh             match self.pop_buddy_block(vaddr, exp, list_guard) {
417c2481452Shoumkh                 Err(err) => {
418c2481452Shoumkh                     return Err(err);
419c2481452Shoumkh                 }
420c2481452Shoumkh                 Ok(buddy_region) => {
421*40fe15e0SLoGin                     let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
422*40fe15e0SLoGin                     let copy_region = region.clone();
423c2481452Shoumkh                     // 在两块内存都被取出之后才进行合并
424a7eb62a4Shoumkh                     match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
425c2481452Shoumkh                         Err(err) => {
426c2481452Shoumkh                             // 如果合并失败了要将取出来的元素放回去
427a7eb62a4Shoumkh                             self.push_block(copy_region, list_guard);
428a7eb62a4Shoumkh                             kdebug!("merge_all_exp: merge_blocks failed");
429c2481452Shoumkh                             return Err(err);
430c2481452Shoumkh                         }
431c2481452Shoumkh                         Ok(_) => continue,
432c2481452Shoumkh                     }
433c2481452Shoumkh                 }
434c2481452Shoumkh             }
435c2481452Shoumkh         }
436c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
437c2481452Shoumkh     }
438c2481452Shoumkh 
439c2481452Shoumkh     /// @brief 合并两个【已经从链表中取出】的内存块
440c2481452Shoumkh     ///
441c2481452Shoumkh     /// @param region_1 第一个内存块
442c2481452Shoumkh     ///
443c2481452Shoumkh     /// @param region_2 第二个内存
444c2481452Shoumkh     ///
445c2481452Shoumkh     /// @return Ok(MmioResult) 成功返回SUCCESS
446c2481452Shoumkh     ///
447c2481452Shoumkh     /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
448a7eb62a4Shoumkh     fn merge_blocks(
449c2481452Shoumkh         &self,
450*40fe15e0SLoGin         region_1: MmioBuddyAddrRegion,
451*40fe15e0SLoGin         region_2: MmioBuddyAddrRegion,
452c2481452Shoumkh         exp: u32,
453c2481452Shoumkh         high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
454c2481452Shoumkh     ) -> Result<MmioResult, MmioResult> {
455c2481452Shoumkh         // 判断是否为伙伴块
456a7eb62a4Shoumkh         if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
457c2481452Shoumkh             return Err(MmioResult::EINVAL);
458c2481452Shoumkh         }
459c2481452Shoumkh         // 将大的块放进下一级链表
460a7eb62a4Shoumkh         self.push_block(region_1, high_list_guard);
461c2481452Shoumkh         return Ok(MmioResult::SUCCESS);
462c2481452Shoumkh     }
463c2481452Shoumkh 
464c2481452Shoumkh     /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
465c2481452Shoumkh     ///
466c2481452Shoumkh     /// @param size mmio区域的大小(字节)
467c2481452Shoumkh     ///
468c2481452Shoumkh     /// @param vm_flags 要把vma设置成的标志
469c2481452Shoumkh     ///
470c2481452Shoumkh     /// @param res_vaddr 返回值-分配得到的虚拟地址
471c2481452Shoumkh     ///
472c2481452Shoumkh     /// @param res_length 返回值-分配的虚拟地址空间长度
473c2481452Shoumkh     ///
474a7eb62a4Shoumkh     /// @return Ok(i32) 成功返回0
475a7eb62a4Shoumkh     ///
476676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
477ef9f9732Shoumkh     pub fn create_mmio(
478a7eb62a4Shoumkh         &self,
479*40fe15e0SLoGin         size: usize,
480*40fe15e0SLoGin         _vm_flags: vm_flags_t,
481c2481452Shoumkh         res_vaddr: *mut u64,
482c2481452Shoumkh         res_length: *mut u64,
483676b8ef6SMork     ) -> Result<i32, SystemError> {
484c2481452Shoumkh         if size > PAGE_1G_SIZE || size == 0 {
485676b8ef6SMork             return Err(SystemError::EPERM);
486c2481452Shoumkh         }
487*40fe15e0SLoGin         let retval: i32 = 0;
488c2481452Shoumkh         // 计算前导0
489*40fe15e0SLoGin         #[cfg(target_arch = "x86_64")]
490*40fe15e0SLoGin         let mut size_exp: u32 = 63 - size.leading_zeros();
491c2481452Shoumkh         // 记录最终申请的空间大小
492*40fe15e0SLoGin         let mut new_size = size;
493c2481452Shoumkh         // 对齐要申请的空间大小
494c2481452Shoumkh         // 如果要申请的空间大小小于4k,则分配4k
495c2481452Shoumkh         if size_exp < PAGE_4K_SHIFT {
496*40fe15e0SLoGin             new_size = PAGE_4K_SIZE as usize;
497c2481452Shoumkh             size_exp = PAGE_4K_SHIFT;
498c2481452Shoumkh         } else if (new_size & (!(1 << size_exp))) != 0 {
499c2481452Shoumkh             // 向左对齐空间大小
500c2481452Shoumkh             size_exp += 1;
501c2481452Shoumkh             new_size = 1 << size_exp;
502c2481452Shoumkh         }
503*40fe15e0SLoGin         match self.mmio_buddy_query_addr_region(size_exp) {
504c2481452Shoumkh             Ok(region) => {
505*40fe15e0SLoGin                 // todo: 是否需要创建vma?或者用新重写的机制去做?
506*40fe15e0SLoGin                 // kdebug!(
507*40fe15e0SLoGin                 //     "create_mmio: vaddr = {:?}, length = {}",
508*40fe15e0SLoGin                 //     region.vaddr,
509*40fe15e0SLoGin                 //     new_size
510*40fe15e0SLoGin                 // );
511*40fe15e0SLoGin                 unsafe { *res_vaddr = region.vaddr.data() as u64 };
512*40fe15e0SLoGin                 unsafe { *res_length = new_size as u64 };
513c2481452Shoumkh             }
514c2481452Shoumkh             Err(_) => {
515*40fe15e0SLoGin                 kerror!("failed to create mmio. pid = {:?}", current_pcb().pid);
516676b8ef6SMork                 return Err(SystemError::ENOMEM);
517c2481452Shoumkh             }
518c2481452Shoumkh         }
519a7eb62a4Shoumkh         return Ok(retval);
520c2481452Shoumkh     }
521c2481452Shoumkh 
522c2481452Shoumkh     /// @brief 取消mmio的映射并将地址空间归还到buddy中
523c2481452Shoumkh     ///
524c2481452Shoumkh     /// @param vaddr 起始的虚拟地址
525c2481452Shoumkh     ///
526c2481452Shoumkh     /// @param length 要归还的地址空间的长度
527c2481452Shoumkh     ///
528c2481452Shoumkh     /// @return Ok(i32) 成功返回0
529c2481452Shoumkh     ///
530676b8ef6SMork     /// @return Err(SystemError) 失败返回错误码
531*40fe15e0SLoGin     pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
532*40fe15e0SLoGin         assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
533*40fe15e0SLoGin         assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
534*40fe15e0SLoGin         if vaddr < self.pool_start_addr
535*40fe15e0SLoGin             || vaddr.data() >= self.pool_start_addr.data() + self.pool_size
536*40fe15e0SLoGin         {
537676b8ef6SMork             return Err(SystemError::EINVAL);
538c2481452Shoumkh         }
539*40fe15e0SLoGin         // todo: 重构MMIO管理机制,创建类似全局的manager之类的,管理MMIO的空间?
540*40fe15e0SLoGin 
541*40fe15e0SLoGin         // 暂时认为传入的vaddr都是正确的
542*40fe15e0SLoGin         let page_count = length / MMArch::PAGE_SIZE;
543*40fe15e0SLoGin         // 取消映射
544*40fe15e0SLoGin         let mut bindings = KernelMapper::lock();
545*40fe15e0SLoGin         let mut kernel_mapper = bindings.as_mut();
546*40fe15e0SLoGin         if kernel_mapper.is_none() {
547*40fe15e0SLoGin             kwarn!("release_mmio: kernel_mapper is read only");
548*40fe15e0SLoGin             return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
549c2481452Shoumkh         }
550*40fe15e0SLoGin 
551*40fe15e0SLoGin         for i in 0..page_count {
552c2481452Shoumkh             unsafe {
553*40fe15e0SLoGin                 kernel_mapper
554*40fe15e0SLoGin                     .as_mut()
555*40fe15e0SLoGin                     .unwrap()
556*40fe15e0SLoGin                     .unmap(vaddr + i * MMArch::PAGE_SIZE, true)
557*40fe15e0SLoGin             };
558c2481452Shoumkh         }
559*40fe15e0SLoGin 
560*40fe15e0SLoGin         // todo: 归还到buddy
561*40fe15e0SLoGin 
562a7eb62a4Shoumkh         return Ok(0);
563a7eb62a4Shoumkh     }
564a7eb62a4Shoumkh }
565a7eb62a4Shoumkh 
566a7eb62a4Shoumkh /// @brief mmio伙伴系统内部的地址区域结构体
567*40fe15e0SLoGin #[derive(Debug, Clone)]
568*40fe15e0SLoGin struct MmioBuddyAddrRegion {
569*40fe15e0SLoGin     vaddr: VirtAddr,
570a7eb62a4Shoumkh }
571a7eb62a4Shoumkh impl MmioBuddyAddrRegion {
572*40fe15e0SLoGin     pub fn new(vaddr: VirtAddr) -> Self {
573*40fe15e0SLoGin         return MmioBuddyAddrRegion { vaddr };
574a7eb62a4Shoumkh     }
575*40fe15e0SLoGin 
576*40fe15e0SLoGin     #[allow(dead_code)]
577*40fe15e0SLoGin     pub fn vaddr(&self) -> VirtAddr {
578*40fe15e0SLoGin         return self.vaddr;
579a7eb62a4Shoumkh     }
580a7eb62a4Shoumkh }
581a7eb62a4Shoumkh 
582a7eb62a4Shoumkh /// @brief 空闲页数组结构体
583*40fe15e0SLoGin #[derive(Debug)]
584a7eb62a4Shoumkh pub struct MmioFreeRegionList {
585a7eb62a4Shoumkh     /// 存储mmio_buddy的地址链表
586*40fe15e0SLoGin     list: LinkedList<MmioBuddyAddrRegion>,
587a7eb62a4Shoumkh     /// 空闲块的数量
588a7eb62a4Shoumkh     num_free: i64,
589a7eb62a4Shoumkh }
590a7eb62a4Shoumkh impl MmioFreeRegionList {
59164aea4b3SGou Ngai     #[allow(dead_code)]
592a7eb62a4Shoumkh     fn new() -> Self {
593a7eb62a4Shoumkh         return MmioFreeRegionList {
594a7eb62a4Shoumkh             ..Default::default()
595a7eb62a4Shoumkh         };
596a7eb62a4Shoumkh     }
597a7eb62a4Shoumkh }
598a7eb62a4Shoumkh impl Default for MmioFreeRegionList {
599a7eb62a4Shoumkh     fn default() -> Self {
600a7eb62a4Shoumkh         MmioFreeRegionList {
601a7eb62a4Shoumkh             list: Default::default(),
602a7eb62a4Shoumkh             num_free: 0,
603a7eb62a4Shoumkh         }
604a7eb62a4Shoumkh     }
605a7eb62a4Shoumkh }
606a7eb62a4Shoumkh 
607a7eb62a4Shoumkh /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
608a7eb62a4Shoumkh ///
609a7eb62a4Shoumkh /// @param exp内存大小
610a7eb62a4Shoumkh ///
611a7eb62a4Shoumkh /// @return 内存池数组下标
612a7eb62a4Shoumkh #[inline(always)]
613a7eb62a4Shoumkh fn exp2index(exp: u32) -> usize {
614a7eb62a4Shoumkh     return (exp - 12) as usize;
615a7eb62a4Shoumkh }
616a7eb62a4Shoumkh 
617*40fe15e0SLoGin pub fn mmio_init() {
618*40fe15e0SLoGin     kdebug!("Initializing MMIO buddy memory pool...");
619*40fe15e0SLoGin     // 初始化mmio内存池
620*40fe15e0SLoGin     unsafe {
621*40fe15e0SLoGin         __MMIO_POOL = Some(MmioBuddyMemPool::new());
622*40fe15e0SLoGin     }
623*40fe15e0SLoGin 
624*40fe15e0SLoGin     kinfo!("MMIO buddy memory pool init done");
625*40fe15e0SLoGin }
626a7eb62a4Shoumkh /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
627a7eb62a4Shoumkh ///
628a7eb62a4Shoumkh /// @param size mmio区域的大小(字节)
629a7eb62a4Shoumkh ///
630a7eb62a4Shoumkh /// @param vm_flags 要把vma设置成的标志
631a7eb62a4Shoumkh ///
632a7eb62a4Shoumkh /// @param res_vaddr 返回值-分配得到的虚拟地址
633a7eb62a4Shoumkh ///
634a7eb62a4Shoumkh /// @param res_length 返回值-分配的虚拟地址空间长度
635a7eb62a4Shoumkh ///
636a7eb62a4Shoumkh /// @return int 错误码
637a7eb62a4Shoumkh #[no_mangle]
638a7eb62a4Shoumkh pub extern "C" fn mmio_create(
639a7eb62a4Shoumkh     size: u32,
640a7eb62a4Shoumkh     vm_flags: vm_flags_t,
641a7eb62a4Shoumkh     res_vaddr: *mut u64,
642a7eb62a4Shoumkh     res_length: *mut u64,
643a7eb62a4Shoumkh ) -> i32 {
644*40fe15e0SLoGin     // kdebug!("mmio_create");
645*40fe15e0SLoGin     if let Err(err) = mmio_pool().create_mmio(size as usize, vm_flags, res_vaddr, res_length) {
646676b8ef6SMork         return err.to_posix_errno();
647a7eb62a4Shoumkh     } else {
648c2481452Shoumkh         return 0;
649c2481452Shoumkh     }
650a7eb62a4Shoumkh }
651a7eb62a4Shoumkh 
652a7eb62a4Shoumkh /// @brief 取消mmio的映射并将地址空间归还到buddy中
653a7eb62a4Shoumkh ///
654a7eb62a4Shoumkh /// @param vaddr 起始的虚拟地址
655a7eb62a4Shoumkh ///
656a7eb62a4Shoumkh /// @param length 要归还的地址空间的长度
657a7eb62a4Shoumkh ///
658a7eb62a4Shoumkh /// @return Ok(i32) 成功返回0
659a7eb62a4Shoumkh ///
660a7eb62a4Shoumkh /// @return Err(i32) 失败返回错误码
661a7eb62a4Shoumkh #[no_mangle]
662a7eb62a4Shoumkh pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
663*40fe15e0SLoGin     return mmio_pool()
664*40fe15e0SLoGin         .release_mmio(VirtAddr::new(vaddr as usize), length as usize)
665*40fe15e0SLoGin         .unwrap_or_else(|err| err.to_posix_errno());
666a7eb62a4Shoumkh }
667