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