1 use crate::libs::align::{page_align_down, page_align_up};
2 use crate::libs::spinlock::{SpinLock, SpinLockGuard};
3 use crate::mm::kernel_mapper::KernelMapper;
4 use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
5 use crate::mm::{MMArch, MemoryManagementArch};
6 use crate::process::ProcessManager;
7
8 use alloc::{collections::LinkedList, vec::Vec};
9 use core::mem;
10 use core::mem::MaybeUninit;
11 use core::sync::atomic::{AtomicBool, Ordering};
12 use log::{debug, error, info, warn};
13 use system_error::SystemError;
14
15 use super::page::{EntryFlags, PAGE_4K_SIZE};
16 use super::{PhysAddr, VirtAddr};
17
18 // 最大的伙伴块的幂
19 const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT as u32;
20 // 最小的伙伴块的幂
21 const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT as u32;
22 // 内存池数组的范围
23 const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
24
25 const PAGE_1G_SIZE: usize = 1 << 30;
26
27 static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
28
mmio_pool() -> &'static MmioBuddyMemPool29 pub fn mmio_pool() -> &'static MmioBuddyMemPool {
30 unsafe { __MMIO_POOL.as_ref().unwrap() }
31 }
32
33 pub enum MmioResult {
34 SUCCESS,
35 EINVAL,
36 ENOFOUND,
37 WRONGEXP,
38 ISEMPTY,
39 }
40
41 /// @brief buddy内存池
42 #[derive(Debug)]
43 pub struct MmioBuddyMemPool {
44 pool_start_addr: VirtAddr,
45 pool_size: usize,
46 free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
47 }
48
49 impl MmioBuddyMemPool {
50 #[inline(never)]
new() -> Self51 fn new() -> Self {
52 let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
53 MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
54 for i in 0..MMIO_BUDDY_REGION_COUNT {
55 free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
56 }
57 let free_regions = unsafe {
58 mem::transmute::<
59 [core::mem::MaybeUninit<
60 crate::libs::spinlock::SpinLock<crate::mm::mmio_buddy::MmioFreeRegionList>,
61 >; MMIO_BUDDY_REGION_COUNT as usize],
62 [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
63 >(free_regions)
64 };
65
66 let pool = MmioBuddyMemPool {
67 pool_start_addr: MMArch::MMIO_BASE,
68 pool_size: MMArch::MMIO_SIZE,
69 free_regions,
70 };
71
72 assert!(pool.pool_start_addr.data() % PAGE_1G_SIZE == 0);
73 debug!("MMIO buddy pool init: created");
74
75 let mut vaddr_base = MMArch::MMIO_BASE;
76 let mut remain_size = MMArch::MMIO_SIZE;
77 debug!(
78 "BASE: {:?}, TOP: {:?}, size: {:?}",
79 MMArch::MMIO_BASE,
80 MMArch::MMIO_TOP,
81 MMArch::MMIO_SIZE
82 );
83
84 for shift in (PAGE_4K_SHIFT..=PAGE_1G_SHIFT).rev() {
85 if remain_size & (1 << shift) != 0 {
86 let ok = pool.give_back_block(vaddr_base, shift as u32).is_ok();
87 if ok {
88 vaddr_base += 1 << shift;
89 remain_size -= 1 << shift;
90 } else {
91 panic!("MMIO buddy pool init failed");
92 }
93 }
94 }
95
96 debug!("MMIO buddy pool init success");
97 return pool;
98 }
99
100 /// @brief 创建新的地址区域结构体
101 ///
102 /// @param vaddr 虚拟地址
103 ///
104 /// @return 创建好的地址区域结构体
create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion105 fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
106 // debug!("create_region for vaddr: {vaddr:?}");
107
108 let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
109
110 // debug!("create_region for vaddr: {vaddr:?} OK!!!");
111 return region;
112 }
113
114 /// @brief 将内存块归还给buddy
115 ///
116 /// @param vaddr 虚拟地址
117 ///
118 /// @param exp 内存空间的大小(2^exp)
119 ///
120 /// @param list_guard 【exp】对应的链表
121 ///
122 /// @return Ok(i32) 返回0
123 ///
124 /// @return Err(SystemError) 返回错误码
give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError>125 fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
126 // 确保内存对齐,低位都要为0
127 if (vaddr.data() & ((1 << exp) - 1)) != 0 {
128 return Err(SystemError::EINVAL);
129 }
130 let region: MmioBuddyAddrRegion = self.create_region(vaddr);
131 // 加入buddy
132 let mut list_guard = self.free_regions[exp2index(exp)].lock();
133
134 self.push_block(region, &mut list_guard);
135 return Ok(0);
136 }
137
138 /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中
139 ///
140 /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
141 ///
142 /// @param exp 要被分割的地址区域的大小的幂
143 ///
144 /// @param list_guard 【exp-1】对应的链表
split_block( &self, region: MmioBuddyAddrRegion, exp: u32, low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, )145 fn split_block(
146 &self,
147 region: MmioBuddyAddrRegion,
148 exp: u32,
149 low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
150 ) {
151 let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
152 let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
153 self.push_block(region, low_list_guard);
154 self.push_block(new_region, low_list_guard);
155 }
156
157 /// @brief 从buddy中申请一块指定大小的内存区域
158 ///
159 /// @param exp 要申请的内存块的大小的幂(2^exp)
160 ///
161 /// @param list_guard exp对应的链表
162 ///
163 /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
164 ///
165 /// @return Err(MmioResult)
166 /// - 没有满足要求的内存块时,返回ENOFOUND
167 /// - 申请的内存块大小超过合法范围,返回WRONGEXP
168 /// - 调用函数出错时,返回出错函数对应错误码
query_addr_region( &self, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioBuddyAddrRegion, MmioResult>169 fn query_addr_region(
170 &self,
171 exp: u32,
172 list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
173 ) -> Result<MmioBuddyAddrRegion, MmioResult> {
174 // 申请范围错误
175 if !(MMIO_BUDDY_MIN_EXP..=MMIO_BUDDY_MAX_EXP).contains(&exp) {
176 debug!("query_addr_region: exp wrong");
177 return Err(MmioResult::WRONGEXP);
178 }
179 // 没有恰好符合要求的内存块
180 // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】
181 if list_guard.num_free == 0 {
182 // 找到最小符合申请范围的内存块
183 // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp
184 for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
185 let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
186 &mut self.free_regions[exp2index(e)].lock();
187 if pop_list.num_free == 0 {
188 continue;
189 }
190
191 for e2 in (exp + 1..e + 1).rev() {
192 if e2 == e {
193 match self.pop_block(pop_list) {
194 Ok(region) => {
195 if e2 != exp + 1 {
196 // 要将分裂后的内存块插入到更小的链表中
197 let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
198 &mut self.free_regions[exp2index(e2 - 1)].lock();
199 self.split_block(region, e2, low_list_guard);
200 } else {
201 // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
202 // 所以直接将list_guard传入
203 self.split_block(region, e2, list_guard);
204 }
205 }
206 Err(err) => {
207 debug!("buddy_pop_region get wrong");
208 return Err(err);
209 }
210 }
211 } else {
212 match self.pop_block(&mut self.free_regions[exp2index(e2)].lock()) {
213 Ok(region) => {
214 if e2 != exp + 1 {
215 // 要将分裂后的内存块插入到更小的链表中
216 let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
217 &mut self.free_regions[exp2index(e2 - 1)].lock();
218 self.split_block(region, e2, low_list_guard);
219 } else {
220 // 由于exp对应的链表list_guard已经被锁住了 不能再加锁
221 // 所以直接将list_guard传入
222 self.split_block(region, e2, list_guard);
223 }
224 }
225 Err(err) => {
226 debug!("buddy_pop_region get wrong");
227 return Err(err);
228 }
229 }
230 }
231 }
232 break;
233 }
234 // 判断是否获得了exp大小的内存块
235 if list_guard.num_free > 0 {
236 match self.pop_block(list_guard) {
237 Ok(ret) => return Ok(ret),
238 Err(err) => return Err(err),
239 }
240 }
241 // 拆分大内存块无法获得exp大小内存块
242 // 尝试用小内存块合成
243 // 即将两块exp合成一块exp+1
244
245 // TODO:修改下一个循环的冗余代码,请不要删除此处的注释
246 // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
247 // if let Err(err) = self.merge_all_exp(
248 // exp,
249 // &mut self.free_regions[exp2index(exp) as usize].lock(),
250 // high_list_guard,
251 // ) {
252 // return err;
253 // } else {
254 // return MmioResult::SUCCESS;
255 // }
256 // };
257 for e in MMIO_BUDDY_MIN_EXP..exp {
258 if e != exp - 1 {
259 match self.merge_all_exp(
260 exp,
261 &mut self.free_regions[exp2index(exp)].lock(),
262 &mut self.free_regions[exp2index(exp + 1)].lock(),
263 ) {
264 Ok(_) => continue,
265 Err(err) => {
266 debug!("merge_all_exp get wrong");
267 return Err(err);
268 }
269 }
270 } else {
271 match self.merge_all_exp(
272 exp,
273 &mut self.free_regions[exp2index(exp)].lock(),
274 list_guard,
275 ) {
276 Ok(_) => continue,
277 Err(err) => {
278 debug!("merge_all_exp get wrong");
279 return Err(err);
280 }
281 }
282 }
283 }
284
285 //判断是否获得了exp大小的内存块
286 if list_guard.num_free > 0 {
287 match self.pop_block(list_guard) {
288 Ok(ret) => return Ok(ret),
289 Err(err) => return Err(err),
290 }
291 }
292 return Err(MmioResult::ENOFOUND);
293 } else {
294 match self.pop_block(list_guard) {
295 Ok(ret) => return Ok(ret),
296 Err(err) => return Err(err),
297 }
298 }
299 }
300
301 /// @brief 对query_addr_region进行封装
302 ///
303 /// @param exp 内存区域的大小(2^exp)
304 ///
305 /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
306 /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。
mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult>307 fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
308 let mut list_guard: SpinLockGuard<MmioFreeRegionList> =
309 self.free_regions[exp2index(exp)].lock();
310 match self.query_addr_region(exp, &mut list_guard) {
311 Ok(ret) => return Ok(ret),
312 Err(err) => {
313 debug!("mmio_buddy_query_addr_region failed");
314 return Err(err);
315 }
316 }
317 }
318 /// @brief 往指定的地址空间链表中添加一个地址区域
319 ///
320 /// @param region 要被添加的地址结构体
321 ///
322 /// @param list_guard 目标链表
push_block( &self, region: MmioBuddyAddrRegion, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, )323 fn push_block(
324 &self,
325 region: MmioBuddyAddrRegion,
326 list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
327 ) {
328 list_guard.list.push_back(region);
329 list_guard.num_free += 1;
330 }
331
332 /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
333 #[inline(always)]
calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr334 fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
335 return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
336 }
337
338 /// @brief 寻找并弹出指定内存块的伙伴块
339 ///
340 /// @param region 对应内存块的信息
341 ///
342 /// @param exp 内存块大小
343 ///
344 /// @param list_guard 【exp】对应的链表
345 ///
346 /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
347 /// @return Err(MmioResult)
348 /// - 当链表为空,返回ISEMPTY
349 /// - 没有找到伙伴块,返回ENOFOUND
pop_buddy_block( &self, vaddr: VirtAddr, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioBuddyAddrRegion, MmioResult>350 fn pop_buddy_block(
351 &self,
352 vaddr: VirtAddr,
353 exp: u32,
354 list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
355 ) -> Result<MmioBuddyAddrRegion, MmioResult> {
356 if list_guard.list.is_empty() {
357 return Err(MmioResult::ISEMPTY);
358 } else {
359 //计算伙伴块的地址
360 let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
361
362 // element 只会有一个元素
363 let mut element: Vec<MmioBuddyAddrRegion> = list_guard
364 .list
365 .extract_if(|x| x.vaddr == buddy_vaddr)
366 .collect();
367 if element.len() == 1 {
368 list_guard.num_free -= 1;
369 return Ok(element.pop().unwrap());
370 }
371
372 //没有找到对应的伙伴块
373 return Err(MmioResult::ENOFOUND);
374 }
375 }
376
377 /// @brief 从指定空闲链表中取出内存区域
378 ///
379 /// @param list_guard 【exp】对应的链表
380 ///
381 /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
382 ///
383 /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY
pop_block( &self, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioBuddyAddrRegion, MmioResult>384 fn pop_block(
385 &self,
386 list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
387 ) -> Result<MmioBuddyAddrRegion, MmioResult> {
388 if !list_guard.list.is_empty() {
389 list_guard.num_free -= 1;
390 return Ok(list_guard.list.pop_back().unwrap());
391 }
392 return Err(MmioResult::ISEMPTY);
393 }
394
395 /// @brief 合并所有2^{exp}大小的内存块
396 ///
397 /// @param exp 内存块大小的幂(2^exp)
398 ///
399 /// @param list_guard exp对应的链表
400 ///
401 /// @param high_list_guard exp+1对应的链表
402 ///
403 /// @return Ok(MmioResult) 合并成功返回SUCCESS
404 /// @return Err(MmioResult)
405 /// - 内存块过少,无法合并,返回EINVAL
406 /// - pop_buddy_block调用出错,返回其错误码
407 /// - merge_blocks调用出错,返回其错误码
merge_all_exp( &self, exp: u32, list_guard: &mut SpinLockGuard<MmioFreeRegionList>, high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioResult, MmioResult>408 fn merge_all_exp(
409 &self,
410 exp: u32,
411 list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
412 high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
413 ) -> Result<MmioResult, MmioResult> {
414 // 至少要两个内存块才能合并
415 if list_guard.num_free <= 1 {
416 return Err(MmioResult::EINVAL);
417 }
418 loop {
419 if list_guard.num_free <= 1 {
420 break;
421 }
422 // 获取内存块
423 let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
424 // 获取伙伴内存块
425 match self.pop_buddy_block(vaddr, exp, list_guard) {
426 Err(err) => {
427 return Err(err);
428 }
429 Ok(buddy_region) => {
430 let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
431 let copy_region = region.clone();
432 // 在两块内存都被取出之后才进行合并
433 match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
434 Err(err) => {
435 // 如果合并失败了要将取出来的元素放回去
436 self.push_block(copy_region, list_guard);
437 debug!("merge_all_exp: merge_blocks failed");
438 return Err(err);
439 }
440 Ok(_) => continue,
441 }
442 }
443 }
444 }
445 return Ok(MmioResult::SUCCESS);
446 }
447
448 /// @brief 合并两个【已经从链表中取出】的内存块
449 ///
450 /// @param region_1 第一个内存块
451 ///
452 /// @param region_2 第二个内存
453 ///
454 /// @return Ok(MmioResult) 成功返回SUCCESS
455 ///
456 /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
merge_blocks( &self, region_1: MmioBuddyAddrRegion, region_2: MmioBuddyAddrRegion, exp: u32, high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, ) -> Result<MmioResult, MmioResult>457 fn merge_blocks(
458 &self,
459 region_1: MmioBuddyAddrRegion,
460 region_2: MmioBuddyAddrRegion,
461 exp: u32,
462 high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
463 ) -> Result<MmioResult, MmioResult> {
464 // 判断是否为伙伴块
465 if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
466 return Err(MmioResult::EINVAL);
467 }
468 // 将大的块放进下一级链表
469 self.push_block(region_1, high_list_guard);
470 return Ok(MmioResult::SUCCESS);
471 }
472
473 /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
474 ///
475 /// @param size mmio区域的大小(字节)
476 ///
477 /// @param vm_flags 要把vma设置成的标志
478 ///
479 /// @param res_vaddr 返回值-分配得到的虚拟地址
480 ///
481 /// @param res_length 返回值-分配的虚拟地址空间长度
482 ///
483 /// @return Ok(i32) 成功返回0
484 ///
485 /// @return Err(SystemError) 失败返回错误码
create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError>486 pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
487 if size > PAGE_1G_SIZE || size == 0 {
488 return Err(SystemError::EPERM);
489 }
490 // 计算前导0
491 #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
492 let mut size_exp: u32 = 63 - size.leading_zeros();
493 // debug!("create_mmio: size_exp: {}", size_exp);
494 // 记录最终申请的空间大小
495 let mut new_size = size;
496 // 对齐要申请的空间大小
497 // 如果要申请的空间大小小于4k,则分配4k
498 if size_exp < PAGE_4K_SHIFT as u32 {
499 new_size = PAGE_4K_SIZE;
500 size_exp = PAGE_4K_SHIFT as u32;
501 } else if (new_size & (!(1 << size_exp))) != 0 {
502 // 向左对齐空间大小
503 size_exp += 1;
504 new_size = 1 << size_exp;
505 }
506 match self.mmio_buddy_query_addr_region(size_exp) {
507 Ok(region) => {
508 let space_guard =
509 unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) };
510 return Ok(space_guard);
511 }
512 Err(_) => {
513 error!(
514 "failed to create mmio. pid = {:?}",
515 ProcessManager::current_pcb().pid()
516 );
517 return Err(SystemError::ENOMEM);
518 }
519 }
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 warn!("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 let x: Option<(
554 PhysAddr,
555 EntryFlags<MMArch>,
556 crate::mm::page::PageFlush<MMArch>,
557 )> = kernel_mapper
558 .as_mut()
559 .unwrap()
560 .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, false);
561 if let Some((_, _, flush)) = x {
562 flush.flush();
563 }
564 };
565 }
566
567 // 归还到buddy
568 mmio_pool()
569 .give_back_block(vaddr, length.trailing_zeros())
570 .unwrap_or_else(|err| {
571 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
572 });
573
574 return Ok(0);
575 }
576 }
577
578 /// @brief mmio伙伴系统内部的地址区域结构体
579 #[derive(Debug, Clone)]
580 struct MmioBuddyAddrRegion {
581 vaddr: VirtAddr,
582 }
583 impl MmioBuddyAddrRegion {
new(vaddr: VirtAddr) -> Self584 pub fn new(vaddr: VirtAddr) -> Self {
585 return MmioBuddyAddrRegion { vaddr };
586 }
587
588 #[allow(dead_code)]
vaddr(&self) -> VirtAddr589 pub fn vaddr(&self) -> VirtAddr {
590 return self.vaddr;
591 }
592 }
593
594 /// @brief 空闲页数组结构体
595 #[derive(Debug, Default)]
596 pub struct MmioFreeRegionList {
597 /// 存储mmio_buddy的地址链表
598 list: LinkedList<MmioBuddyAddrRegion>,
599 /// 空闲块的数量
600 num_free: i64,
601 }
602 impl MmioFreeRegionList {
603 #[allow(dead_code)]
new() -> Self604 fn new() -> Self {
605 return MmioFreeRegionList {
606 ..Default::default()
607 };
608 }
609 }
610
611 /// @brief 将内存对象大小的幂转换成内存池中的数组的下标
612 ///
613 /// @param exp内存大小
614 ///
615 /// @return 内存池数组下标
616 #[inline(always)]
exp2index(exp: u32) -> usize617 fn exp2index(exp: u32) -> usize {
618 return (exp - 12) as usize;
619 }
620
621 #[derive(Debug)]
622 pub struct MMIOSpaceGuard {
623 vaddr: VirtAddr,
624 size: usize,
625 mapped: AtomicBool,
626 }
627
628 impl MMIOSpaceGuard {
from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self629 pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self {
630 // check size
631 assert!(
632 size & (MMArch::PAGE_SIZE - 1) == 0,
633 "MMIO space size must be page aligned"
634 );
635 assert!(size.is_power_of_two(), "MMIO space size must be power of 2");
636 assert!(
637 vaddr.check_aligned(size),
638 "MMIO space vaddr must be aligned with size"
639 );
640 assert!(
641 vaddr.data() >= MMArch::MMIO_BASE.data()
642 && vaddr.data() + size <= MMArch::MMIO_TOP.data(),
643 "MMIO space must be in MMIO region"
644 );
645
646 // 人工创建的MMIO空间,认为已经映射
647 MMIOSpaceGuard {
648 vaddr,
649 size,
650 mapped: AtomicBool::new(mapped),
651 }
652 }
653
vaddr(&self) -> VirtAddr654 pub fn vaddr(&self) -> VirtAddr {
655 self.vaddr
656 }
657
size(&self) -> usize658 pub fn size(&self) -> usize {
659 self.size
660 }
661
662 /// 将物理地址填写到虚拟地址空间中
663 ///
664 /// ## Safety
665 ///
666 /// 传入的物理地址【一定要是设备的物理地址】。
667 /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError>668 pub unsafe fn map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError> {
669 if length > self.size {
670 return Err(SystemError::EINVAL);
671 }
672
673 let check = self
674 .mapped
675 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
676 if check.is_err() {
677 return Err(SystemError::EINVAL);
678 }
679
680 let flags = EntryFlags::mmio_flags();
681
682 let mut kernel_mapper = KernelMapper::lock();
683 let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
684 return r;
685 }
686
687 /// 将物理地址填写到虚拟地址空间中
688 ///
689 /// ## Safety
690 ///
691 /// 传入的物理地址【一定要是设备的物理地址】。
692 /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
map_phys_with_flags( &self, paddr: PhysAddr, length: usize, flags: EntryFlags<MMArch>, ) -> Result<(), SystemError>693 pub unsafe fn map_phys_with_flags(
694 &self,
695 paddr: PhysAddr,
696 length: usize,
697 flags: EntryFlags<MMArch>,
698 ) -> Result<(), SystemError> {
699 if length > self.size {
700 return Err(SystemError::EINVAL);
701 }
702
703 let check = self
704 .mapped
705 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
706 if check.is_err() {
707 return Err(SystemError::EINVAL);
708 }
709
710 let mut kernel_mapper = KernelMapper::lock();
711 let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
712 return r;
713 }
714
715 /// # map_any_phys - 将任意物理地址映射到虚拟地址
716 ///
717 /// 将指定的物理地址和长度映射到虚拟地址空间。
718 ///
719 /// ## 参数
720 ///
721 /// - `paddr`: 物理地址,需要被映射的起始地址。
722 /// - `length`: 要映射的物理地址长度。
723 ///
724 /// ## 返回值
725 /// - `Ok(VirtAddr)`: 映射成功,返回虚拟地址的起始地址。
726 /// - `Err(SystemError)`: 映射失败,返回系统错误。
727 ///
728 /// ## 副作用
729 ///
730 /// 该函数会修改虚拟地址空间,将物理地址映射到虚拟地址。
731 ///
732 /// ## Safety
733 ///
734 /// 由于该函数涉及到内存操作,因此它是非安全的。确保在调用该函数时,你传入的物理地址是正确的。
735 #[allow(dead_code)]
map_any_phys( &self, paddr: PhysAddr, length: usize, ) -> Result<VirtAddr, SystemError>736 pub unsafe fn map_any_phys(
737 &self,
738 paddr: PhysAddr,
739 length: usize,
740 ) -> Result<VirtAddr, SystemError> {
741 let paddr_base = PhysAddr::new(page_align_down(paddr.data()));
742 let offset = paddr - paddr_base;
743 let vaddr_base = self.vaddr;
744 let vaddr = vaddr_base + offset;
745
746 self.map_phys(paddr_base, page_align_up(length + offset))?;
747 return Ok(vaddr);
748 }
749
750 /// 泄露一个MMIO space guard,不会释放映射的空间
leak(self)751 pub unsafe fn leak(self) {
752 core::mem::forget(self);
753 }
754 }
755
756 impl Drop for MMIOSpaceGuard {
drop(&mut self)757 fn drop(&mut self) {
758 let _ = mmio_pool()
759 .release_mmio(self.vaddr, self.size)
760 .unwrap_or_else(|err| {
761 panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
762 });
763 }
764 }
765
mmio_init()766 pub fn mmio_init() {
767 debug!("Initializing MMIO buddy memory pool...");
768 // 初始化mmio内存池
769 unsafe {
770 __MMIO_POOL = Some(MmioBuddyMemPool::new());
771 }
772
773 info!("MMIO buddy memory pool init done");
774 }
775