mmio_buddy.rs 25 KB

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