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