10102d69fSLoGin use crate::libs::align::{page_align_down, page_align_up}; 2a7eb62a4Shoumkh use crate::libs::spinlock::{SpinLock, SpinLockGuard}; 340fe15e0SLoGin use crate::mm::kernel_mapper::KernelMapper; 423ef2b33SLoGin use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT}; 52eab6dd7S曾俊 use crate::mm::{MMArch, MemoryManagementArch}; 61496ba7bSLoGin use crate::process::ProcessManager; 72eab6dd7S曾俊 840fe15e0SLoGin use alloc::{collections::LinkedList, vec::Vec}; 940fe15e0SLoGin use core::mem; 1040fe15e0SLoGin use core::mem::MaybeUninit; 1123ef2b33SLoGin use core::sync::atomic::{AtomicBool, Ordering}; 122eab6dd7S曾俊 use log::{debug, error, info, warn}; 1391e9d4abSLoGin use system_error::SystemError; 1440fe15e0SLoGin 15370472f7SLoGin use super::page::{PageFlags, PAGE_4K_SIZE}; 162dd9f0c7SLoGin use super::{PhysAddr, VirtAddr}; 17c2481452Shoumkh 18c2481452Shoumkh // 最大的伙伴块的幂 1923ef2b33SLoGin const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT as u32; 20c2481452Shoumkh // 最小的伙伴块的幂 2123ef2b33SLoGin const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT as u32; 22c2481452Shoumkh // 内存池数组的范围 23c2481452Shoumkh const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1; 24c2481452Shoumkh 2540fe15e0SLoGin const PAGE_1G_SIZE: usize = 1 << 30; 2640fe15e0SLoGin 2740fe15e0SLoGin static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None; 2840fe15e0SLoGin 297ae679ddSLoGin pub fn mmio_pool() -> &'static MmioBuddyMemPool { 307ae679ddSLoGin unsafe { __MMIO_POOL.as_ref().unwrap() } 31c2481452Shoumkh } 32c2481452Shoumkh 33c2481452Shoumkh pub enum MmioResult { 34c2481452Shoumkh SUCCESS, 35c2481452Shoumkh EINVAL, 36c2481452Shoumkh ENOFOUND, 37c2481452Shoumkh WRONGEXP, 38c2481452Shoumkh ISEMPTY, 39c2481452Shoumkh } 40c2481452Shoumkh 41c2481452Shoumkh /// @brief buddy内存池 4240fe15e0SLoGin #[derive(Debug)] 43c2481452Shoumkh pub struct MmioBuddyMemPool { 4440fe15e0SLoGin pool_start_addr: VirtAddr, 4540fe15e0SLoGin pool_size: usize, 46c2481452Shoumkh free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize], 47c2481452Shoumkh } 4840fe15e0SLoGin 49c2481452Shoumkh impl MmioBuddyMemPool { 50453452ccSLoGin #[inline(never)] 51c2481452Shoumkh fn new() -> Self { 5240fe15e0SLoGin let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>; 5340fe15e0SLoGin MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() }; 5440fe15e0SLoGin for i in 0..MMIO_BUDDY_REGION_COUNT { 5540fe15e0SLoGin free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new())); 5640fe15e0SLoGin } 5740fe15e0SLoGin let free_regions = unsafe { 58*bd70d2d1SLoGin mem::transmute::< 59*bd70d2d1SLoGin [core::mem::MaybeUninit< 60*bd70d2d1SLoGin crate::libs::spinlock::SpinLock<crate::mm::mmio_buddy::MmioFreeRegionList>, 61*bd70d2d1SLoGin >; MMIO_BUDDY_REGION_COUNT as usize], 62*bd70d2d1SLoGin [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize], 63*bd70d2d1SLoGin >(free_regions) 64c2481452Shoumkh }; 6540fe15e0SLoGin 6640fe15e0SLoGin let pool = MmioBuddyMemPool { 6723ef2b33SLoGin pool_start_addr: MMArch::MMIO_BASE, 6823ef2b33SLoGin pool_size: MMArch::MMIO_SIZE, 6940fe15e0SLoGin free_regions, 7040fe15e0SLoGin }; 7123ef2b33SLoGin 7223ef2b33SLoGin assert!(pool.pool_start_addr.data() % PAGE_1G_SIZE == 0); 732eab6dd7S曾俊 debug!("MMIO buddy pool init: created"); 7440fe15e0SLoGin 7523ef2b33SLoGin let mut vaddr_base = MMArch::MMIO_BASE; 7623ef2b33SLoGin let mut remain_size = MMArch::MMIO_SIZE; 772eab6dd7S曾俊 debug!( 7823ef2b33SLoGin "BASE: {:?}, TOP: {:?}, size: {:?}", 7923ef2b33SLoGin MMArch::MMIO_BASE, 8023ef2b33SLoGin MMArch::MMIO_TOP, 8123ef2b33SLoGin MMArch::MMIO_SIZE 8223ef2b33SLoGin ); 8323ef2b33SLoGin 8423ef2b33SLoGin for shift in (PAGE_4K_SHIFT..=PAGE_1G_SHIFT).rev() { 8523ef2b33SLoGin if remain_size & (1 << shift) != 0 { 8623ef2b33SLoGin let ok = pool.give_back_block(vaddr_base, shift as u32).is_ok(); 8723ef2b33SLoGin if ok { 8823ef2b33SLoGin vaddr_base += 1 << shift; 8923ef2b33SLoGin remain_size -= 1 << shift; 9023ef2b33SLoGin } else { 9140fe15e0SLoGin panic!("MMIO buddy pool init failed"); 9240fe15e0SLoGin } 9340fe15e0SLoGin } 9440fe15e0SLoGin } 9523ef2b33SLoGin 962eab6dd7S曾俊 debug!("MMIO buddy pool init success"); 9740fe15e0SLoGin return pool; 98c2481452Shoumkh } 99c2481452Shoumkh 100c2481452Shoumkh /// @brief 创建新的地址区域结构体 101c2481452Shoumkh /// 102c2481452Shoumkh /// @param vaddr 虚拟地址 103c2481452Shoumkh /// 104c2481452Shoumkh /// @return 创建好的地址区域结构体 10540fe15e0SLoGin fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion { 1062eab6dd7S曾俊 // debug!("create_region for vaddr: {vaddr:?}"); 10740fe15e0SLoGin 10840fe15e0SLoGin let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr); 10940fe15e0SLoGin 1102eab6dd7S曾俊 // debug!("create_region for vaddr: {vaddr:?} OK!!!"); 111c2481452Shoumkh return region; 112c2481452Shoumkh } 113c2481452Shoumkh 114c2481452Shoumkh /// @brief 将内存块归还给buddy 115c2481452Shoumkh /// 116c2481452Shoumkh /// @param vaddr 虚拟地址 117c2481452Shoumkh /// 118c2481452Shoumkh /// @param exp 内存空间的大小(2^exp) 119c2481452Shoumkh /// 120c2481452Shoumkh /// @param list_guard 【exp】对应的链表 121c2481452Shoumkh /// 122c2481452Shoumkh /// @return Ok(i32) 返回0 123c2481452Shoumkh /// 124676b8ef6SMork /// @return Err(SystemError) 返回错误码 12540fe15e0SLoGin fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> { 126c2481452Shoumkh // 确保内存对齐,低位都要为0 12740fe15e0SLoGin if (vaddr.data() & ((1 << exp) - 1)) != 0 { 128676b8ef6SMork return Err(SystemError::EINVAL); 129c2481452Shoumkh } 13040fe15e0SLoGin let region: MmioBuddyAddrRegion = self.create_region(vaddr); 131c2481452Shoumkh // 加入buddy 13240fe15e0SLoGin let mut list_guard = self.free_regions[exp2index(exp)].lock(); 13340fe15e0SLoGin 13440fe15e0SLoGin self.push_block(region, &mut list_guard); 135c2481452Shoumkh return Ok(0); 136c2481452Shoumkh } 137c2481452Shoumkh 138c2481452Shoumkh /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中 139c2481452Shoumkh /// 140c2481452Shoumkh /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出) 141c2481452Shoumkh /// 142c2481452Shoumkh /// @param exp 要被分割的地址区域的大小的幂 143c2481452Shoumkh /// 144c2481452Shoumkh /// @param list_guard 【exp-1】对应的链表 145a7eb62a4Shoumkh fn split_block( 146c2481452Shoumkh &self, 14740fe15e0SLoGin region: MmioBuddyAddrRegion, 148c2481452Shoumkh exp: u32, 149c2481452Shoumkh low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 150c2481452Shoumkh ) { 15140fe15e0SLoGin let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1); 15240fe15e0SLoGin let new_region: MmioBuddyAddrRegion = self.create_region(vaddr); 153a7eb62a4Shoumkh self.push_block(region, low_list_guard); 154a7eb62a4Shoumkh self.push_block(new_region, low_list_guard); 155c2481452Shoumkh } 156c2481452Shoumkh 157c2481452Shoumkh /// @brief 从buddy中申请一块指定大小的内存区域 158c2481452Shoumkh /// 159c2481452Shoumkh /// @param exp 要申请的内存块的大小的幂(2^exp) 160c2481452Shoumkh /// 161c2481452Shoumkh /// @param list_guard exp对应的链表 162c2481452Shoumkh /// 16340fe15e0SLoGin /// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。 164c2481452Shoumkh /// 165c2481452Shoumkh /// @return Err(MmioResult) 166c2481452Shoumkh /// - 没有满足要求的内存块时,返回ENOFOUND 167c2481452Shoumkh /// - 申请的内存块大小超过合法范围,返回WRONGEXP 168c2481452Shoumkh /// - 调用函数出错时,返回出错函数对应错误码 169a7eb62a4Shoumkh fn query_addr_region( 170c2481452Shoumkh &self, 171c2481452Shoumkh exp: u32, 172c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 17340fe15e0SLoGin ) -> Result<MmioBuddyAddrRegion, MmioResult> { 174c2481452Shoumkh // 申请范围错误 175b5b571e0SLoGin if !(MMIO_BUDDY_MIN_EXP..=MMIO_BUDDY_MAX_EXP).contains(&exp) { 1762eab6dd7S曾俊 debug!("query_addr_region: exp wrong"); 177c2481452Shoumkh return Err(MmioResult::WRONGEXP); 178c2481452Shoumkh } 179c2481452Shoumkh // 没有恰好符合要求的内存块 180c2481452Shoumkh // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】 181c2481452Shoumkh if list_guard.num_free == 0 { 182c2481452Shoumkh // 找到最小符合申请范围的内存块 183c2481452Shoumkh // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp 184c2481452Shoumkh for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 { 185ef9f9732Shoumkh let pop_list: &mut SpinLockGuard<MmioFreeRegionList> = 186b5b571e0SLoGin &mut self.free_regions[exp2index(e)].lock(); 187ef9f9732Shoumkh if pop_list.num_free == 0 { 188c2481452Shoumkh continue; 189c2481452Shoumkh } 190ef9f9732Shoumkh 191c2481452Shoumkh for e2 in (exp + 1..e + 1).rev() { 192ef9f9732Shoumkh if e2 == e { 193ef9f9732Shoumkh match self.pop_block(pop_list) { 194ef9f9732Shoumkh Ok(region) => { 195ef9f9732Shoumkh if e2 != exp + 1 { 196ef9f9732Shoumkh // 要将分裂后的内存块插入到更小的链表中 197ef9f9732Shoumkh let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 198b5b571e0SLoGin &mut self.free_regions[exp2index(e2 - 1)].lock(); 199ef9f9732Shoumkh self.split_block(region, e2, low_list_guard); 200ef9f9732Shoumkh } else { 201ef9f9732Shoumkh // 由于exp对应的链表list_guard已经被锁住了 不能再加锁 202ef9f9732Shoumkh // 所以直接将list_guard传入 203ef9f9732Shoumkh self.split_block(region, e2, list_guard); 204ef9f9732Shoumkh } 205ef9f9732Shoumkh } 206ef9f9732Shoumkh Err(err) => { 2072eab6dd7S曾俊 debug!("buddy_pop_region get wrong"); 208ef9f9732Shoumkh return Err(err); 209ef9f9732Shoumkh } 210ef9f9732Shoumkh } 211ef9f9732Shoumkh } else { 212b5b571e0SLoGin match self.pop_block(&mut self.free_regions[exp2index(e2)].lock()) { 213c2481452Shoumkh Ok(region) => { 214c2481452Shoumkh if e2 != exp + 1 { 215c2481452Shoumkh // 要将分裂后的内存块插入到更小的链表中 216c2481452Shoumkh let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 217b5b571e0SLoGin &mut self.free_regions[exp2index(e2 - 1)].lock(); 218a7eb62a4Shoumkh self.split_block(region, e2, low_list_guard); 219c2481452Shoumkh } else { 220c2481452Shoumkh // 由于exp对应的链表list_guard已经被锁住了 不能再加锁 221c2481452Shoumkh // 所以直接将list_guard传入 222a7eb62a4Shoumkh self.split_block(region, e2, list_guard); 223c2481452Shoumkh } 224c2481452Shoumkh } 225c2481452Shoumkh Err(err) => { 2262eab6dd7S曾俊 debug!("buddy_pop_region get wrong"); 227c2481452Shoumkh return Err(err); 228c2481452Shoumkh } 229c2481452Shoumkh } 230c2481452Shoumkh } 231ef9f9732Shoumkh } 232c2481452Shoumkh break; 233c2481452Shoumkh } 234c2481452Shoumkh // 判断是否获得了exp大小的内存块 235c2481452Shoumkh if list_guard.num_free > 0 { 236ef9f9732Shoumkh match self.pop_block(list_guard) { 237ef9f9732Shoumkh Ok(ret) => return Ok(ret), 238ef9f9732Shoumkh Err(err) => return Err(err), 239ef9f9732Shoumkh } 240c2481452Shoumkh } 241c2481452Shoumkh // 拆分大内存块无法获得exp大小内存块 242c2481452Shoumkh // 尝试用小内存块合成 243c2481452Shoumkh // 即将两块exp合成一块exp+1 244ef9f9732Shoumkh 245ef9f9732Shoumkh // TODO:修改下一个循环的冗余代码,请不要删除此处的注释 246ef9f9732Shoumkh // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| { 247ef9f9732Shoumkh // if let Err(err) = self.merge_all_exp( 248ef9f9732Shoumkh // exp, 249ef9f9732Shoumkh // &mut self.free_regions[exp2index(exp) as usize].lock(), 250ef9f9732Shoumkh // high_list_guard, 251ef9f9732Shoumkh // ) { 252ef9f9732Shoumkh // return err; 253ef9f9732Shoumkh // } else { 254ef9f9732Shoumkh // return MmioResult::SUCCESS; 255ef9f9732Shoumkh // } 256ef9f9732Shoumkh // }; 257c2481452Shoumkh for e in MMIO_BUDDY_MIN_EXP..exp { 258c2481452Shoumkh if e != exp - 1 { 259a7eb62a4Shoumkh match self.merge_all_exp( 260ef9f9732Shoumkh exp, 261b5b571e0SLoGin &mut self.free_regions[exp2index(exp)].lock(), 262ef9f9732Shoumkh &mut self.free_regions[exp2index(exp + 1)].lock(), 263c2481452Shoumkh ) { 264c2481452Shoumkh Ok(_) => continue, 265c2481452Shoumkh Err(err) => { 2662eab6dd7S曾俊 debug!("merge_all_exp get wrong"); 267c2481452Shoumkh return Err(err); 268c2481452Shoumkh } 269c2481452Shoumkh } 270c2481452Shoumkh } else { 271a7eb62a4Shoumkh match self.merge_all_exp( 272ef9f9732Shoumkh exp, 273b5b571e0SLoGin &mut self.free_regions[exp2index(exp)].lock(), 274c2481452Shoumkh list_guard, 275c2481452Shoumkh ) { 276c2481452Shoumkh Ok(_) => continue, 277c2481452Shoumkh Err(err) => { 2782eab6dd7S曾俊 debug!("merge_all_exp get wrong"); 279c2481452Shoumkh return Err(err); 280c2481452Shoumkh } 281c2481452Shoumkh } 282c2481452Shoumkh } 283c2481452Shoumkh } 284c2481452Shoumkh 285c2481452Shoumkh //判断是否获得了exp大小的内存块 286c2481452Shoumkh if list_guard.num_free > 0 { 287ef9f9732Shoumkh match self.pop_block(list_guard) { 288ef9f9732Shoumkh Ok(ret) => return Ok(ret), 289ef9f9732Shoumkh Err(err) => return Err(err), 290ef9f9732Shoumkh } 291c2481452Shoumkh } 292c2481452Shoumkh return Err(MmioResult::ENOFOUND); 293c2481452Shoumkh } else { 294ef9f9732Shoumkh match self.pop_block(list_guard) { 295ef9f9732Shoumkh Ok(ret) => return Ok(ret), 296ef9f9732Shoumkh Err(err) => return Err(err), 297ef9f9732Shoumkh } 298c2481452Shoumkh } 299c2481452Shoumkh } 300c2481452Shoumkh 301c2481452Shoumkh /// @brief 对query_addr_region进行封装 302c2481452Shoumkh /// 303c2481452Shoumkh /// @param exp 内存区域的大小(2^exp) 304c2481452Shoumkh /// 30540fe15e0SLoGin /// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。 306c2481452Shoumkh /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。 30740fe15e0SLoGin fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> { 30823ef2b33SLoGin let mut list_guard: SpinLockGuard<MmioFreeRegionList> = 30923ef2b33SLoGin self.free_regions[exp2index(exp)].lock(); 31023ef2b33SLoGin match self.query_addr_region(exp, &mut list_guard) { 311c2481452Shoumkh Ok(ret) => return Ok(ret), 312c2481452Shoumkh Err(err) => { 3132eab6dd7S曾俊 debug!("mmio_buddy_query_addr_region failed"); 314c2481452Shoumkh return Err(err); 315c2481452Shoumkh } 316c2481452Shoumkh } 317c2481452Shoumkh } 318c2481452Shoumkh /// @brief 往指定的地址空间链表中添加一个地址区域 319c2481452Shoumkh /// 320c2481452Shoumkh /// @param region 要被添加的地址结构体 321c2481452Shoumkh /// 322c2481452Shoumkh /// @param list_guard 目标链表 323a7eb62a4Shoumkh fn push_block( 324c2481452Shoumkh &self, 32540fe15e0SLoGin region: MmioBuddyAddrRegion, 326c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 327c2481452Shoumkh ) { 328c2481452Shoumkh list_guard.list.push_back(region); 329c2481452Shoumkh list_guard.num_free += 1; 330c2481452Shoumkh } 331c2481452Shoumkh 332c2481452Shoumkh /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址 333c2481452Shoumkh #[inline(always)] 33440fe15e0SLoGin fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr { 33540fe15e0SLoGin return VirtAddr::new(vaddr.data() ^ (1 << exp as usize)); 336c2481452Shoumkh } 337c2481452Shoumkh 338c2481452Shoumkh /// @brief 寻找并弹出指定内存块的伙伴块 339c2481452Shoumkh /// 340c2481452Shoumkh /// @param region 对应内存块的信息 341c2481452Shoumkh /// 342c2481452Shoumkh /// @param exp 内存块大小 343c2481452Shoumkh /// 344c2481452Shoumkh /// @param list_guard 【exp】对应的链表 345c2481452Shoumkh /// 346c2481452Shoumkh /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用 347c2481452Shoumkh /// @return Err(MmioResult) 348c2481452Shoumkh /// - 当链表为空,返回ISEMPTY 349c2481452Shoumkh /// - 没有找到伙伴块,返回ENOFOUND 350a7eb62a4Shoumkh fn pop_buddy_block( 351c2481452Shoumkh &self, 35240fe15e0SLoGin vaddr: VirtAddr, 353c2481452Shoumkh exp: u32, 354c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 35540fe15e0SLoGin ) -> Result<MmioBuddyAddrRegion, MmioResult> { 356b5b571e0SLoGin if list_guard.list.is_empty() { 357c2481452Shoumkh return Err(MmioResult::ISEMPTY); 358c2481452Shoumkh } else { 359c2481452Shoumkh //计算伙伴块的地址 360a7eb62a4Shoumkh let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp); 361c2481452Shoumkh 362c2481452Shoumkh // element 只会有一个元素 36340fe15e0SLoGin let mut element: Vec<MmioBuddyAddrRegion> = list_guard 364c2481452Shoumkh .list 3651a72a751SLoGin .extract_if(|x| x.vaddr == buddy_vaddr) 366c2481452Shoumkh .collect(); 367c2481452Shoumkh if element.len() == 1 { 368c2481452Shoumkh list_guard.num_free -= 1; 369c2481452Shoumkh return Ok(element.pop().unwrap()); 370c2481452Shoumkh } 371c2481452Shoumkh 372c2481452Shoumkh //没有找到对应的伙伴块 373c2481452Shoumkh return Err(MmioResult::ENOFOUND); 374c2481452Shoumkh } 375c2481452Shoumkh } 376c2481452Shoumkh 377c2481452Shoumkh /// @brief 从指定空闲链表中取出内存区域 378c2481452Shoumkh /// 379c2481452Shoumkh /// @param list_guard 【exp】对应的链表 380c2481452Shoumkh /// 38140fe15e0SLoGin /// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。 382c2481452Shoumkh /// 383c2481452Shoumkh /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY 384a7eb62a4Shoumkh fn pop_block( 385c2481452Shoumkh &self, 386c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 38740fe15e0SLoGin ) -> Result<MmioBuddyAddrRegion, MmioResult> { 388c2481452Shoumkh if !list_guard.list.is_empty() { 389c2481452Shoumkh list_guard.num_free -= 1; 390c2481452Shoumkh return Ok(list_guard.list.pop_back().unwrap()); 391c2481452Shoumkh } 392c2481452Shoumkh return Err(MmioResult::ISEMPTY); 393c2481452Shoumkh } 394c2481452Shoumkh 395c2481452Shoumkh /// @brief 合并所有2^{exp}大小的内存块 396c2481452Shoumkh /// 397c2481452Shoumkh /// @param exp 内存块大小的幂(2^exp) 398c2481452Shoumkh /// 399c2481452Shoumkh /// @param list_guard exp对应的链表 400c2481452Shoumkh /// 401c2481452Shoumkh /// @param high_list_guard exp+1对应的链表 402c2481452Shoumkh /// 403c2481452Shoumkh /// @return Ok(MmioResult) 合并成功返回SUCCESS 404c2481452Shoumkh /// @return Err(MmioResult) 405c2481452Shoumkh /// - 内存块过少,无法合并,返回EINVAL 406a7eb62a4Shoumkh /// - pop_buddy_block调用出错,返回其错误码 407a7eb62a4Shoumkh /// - merge_blocks调用出错,返回其错误码 408a7eb62a4Shoumkh fn merge_all_exp( 409c2481452Shoumkh &self, 410c2481452Shoumkh exp: u32, 411c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 412c2481452Shoumkh high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 413c2481452Shoumkh ) -> Result<MmioResult, MmioResult> { 414c2481452Shoumkh // 至少要两个内存块才能合并 415c2481452Shoumkh if list_guard.num_free <= 1 { 416c2481452Shoumkh return Err(MmioResult::EINVAL); 417c2481452Shoumkh } 418c2481452Shoumkh loop { 419c2481452Shoumkh if list_guard.num_free <= 1 { 420c2481452Shoumkh break; 421c2481452Shoumkh } 422c2481452Shoumkh // 获取内存块 42340fe15e0SLoGin let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr; 424c2481452Shoumkh // 获取伙伴内存块 425a7eb62a4Shoumkh match self.pop_buddy_block(vaddr, exp, list_guard) { 426c2481452Shoumkh Err(err) => { 427c2481452Shoumkh return Err(err); 428c2481452Shoumkh } 429c2481452Shoumkh Ok(buddy_region) => { 43040fe15e0SLoGin let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap(); 43140fe15e0SLoGin let copy_region = region.clone(); 432c2481452Shoumkh // 在两块内存都被取出之后才进行合并 433a7eb62a4Shoumkh match self.merge_blocks(region, buddy_region, exp, high_list_guard) { 434c2481452Shoumkh Err(err) => { 435c2481452Shoumkh // 如果合并失败了要将取出来的元素放回去 436a7eb62a4Shoumkh self.push_block(copy_region, list_guard); 4372eab6dd7S曾俊 debug!("merge_all_exp: merge_blocks failed"); 438c2481452Shoumkh return Err(err); 439c2481452Shoumkh } 440c2481452Shoumkh Ok(_) => continue, 441c2481452Shoumkh } 442c2481452Shoumkh } 443c2481452Shoumkh } 444c2481452Shoumkh } 445c2481452Shoumkh return Ok(MmioResult::SUCCESS); 446c2481452Shoumkh } 447c2481452Shoumkh 448c2481452Shoumkh /// @brief 合并两个【已经从链表中取出】的内存块 449c2481452Shoumkh /// 450c2481452Shoumkh /// @param region_1 第一个内存块 451c2481452Shoumkh /// 452c2481452Shoumkh /// @param region_2 第二个内存 453c2481452Shoumkh /// 454c2481452Shoumkh /// @return Ok(MmioResult) 成功返回SUCCESS 455c2481452Shoumkh /// 456c2481452Shoumkh /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL 457a7eb62a4Shoumkh fn merge_blocks( 458c2481452Shoumkh &self, 45940fe15e0SLoGin region_1: MmioBuddyAddrRegion, 46040fe15e0SLoGin region_2: MmioBuddyAddrRegion, 461c2481452Shoumkh exp: u32, 462c2481452Shoumkh high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 463c2481452Shoumkh ) -> Result<MmioResult, MmioResult> { 464c2481452Shoumkh // 判断是否为伙伴块 465a7eb62a4Shoumkh if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) { 466c2481452Shoumkh return Err(MmioResult::EINVAL); 467c2481452Shoumkh } 468c2481452Shoumkh // 将大的块放进下一级链表 469a7eb62a4Shoumkh self.push_block(region_1, high_list_guard); 470c2481452Shoumkh return Ok(MmioResult::SUCCESS); 471c2481452Shoumkh } 472c2481452Shoumkh 473c2481452Shoumkh /// @brief 创建一块mmio区域,并将vma绑定到initial_mm 474c2481452Shoumkh /// 475c2481452Shoumkh /// @param size mmio区域的大小(字节) 476c2481452Shoumkh /// 477c2481452Shoumkh /// @param vm_flags 要把vma设置成的标志 478c2481452Shoumkh /// 479c2481452Shoumkh /// @param res_vaddr 返回值-分配得到的虚拟地址 480c2481452Shoumkh /// 481c2481452Shoumkh /// @param res_length 返回值-分配的虚拟地址空间长度 482c2481452Shoumkh /// 483a7eb62a4Shoumkh /// @return Ok(i32) 成功返回0 484a7eb62a4Shoumkh /// 485676b8ef6SMork /// @return Err(SystemError) 失败返回错误码 4862dd9f0c7SLoGin pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> { 487c2481452Shoumkh if size > PAGE_1G_SIZE || size == 0 { 488676b8ef6SMork return Err(SystemError::EPERM); 489c2481452Shoumkh } 490c2481452Shoumkh // 计算前导0 4914fda81ceSLoGin #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] 49240fe15e0SLoGin let mut size_exp: u32 = 63 - size.leading_zeros(); 4932eab6dd7S曾俊 // debug!("create_mmio: size_exp: {}", size_exp); 494c2481452Shoumkh // 记录最终申请的空间大小 49540fe15e0SLoGin let mut new_size = size; 496c2481452Shoumkh // 对齐要申请的空间大小 497c2481452Shoumkh // 如果要申请的空间大小小于4k,则分配4k 49823ef2b33SLoGin if size_exp < PAGE_4K_SHIFT as u32 { 499370472f7SLoGin new_size = PAGE_4K_SIZE; 50023ef2b33SLoGin size_exp = PAGE_4K_SHIFT as u32; 501c2481452Shoumkh } else if (new_size & (!(1 << size_exp))) != 0 { 502c2481452Shoumkh // 向左对齐空间大小 503c2481452Shoumkh size_exp += 1; 504c2481452Shoumkh new_size = 1 << size_exp; 505c2481452Shoumkh } 50640fe15e0SLoGin match self.mmio_buddy_query_addr_region(size_exp) { 507c2481452Shoumkh Ok(region) => { 5082dd9f0c7SLoGin let space_guard = 5092dd9f0c7SLoGin unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) }; 5102dd9f0c7SLoGin return Ok(space_guard); 511c2481452Shoumkh } 512c2481452Shoumkh Err(_) => { 5132eab6dd7S曾俊 error!( 5141496ba7bSLoGin "failed to create mmio. pid = {:?}", 5151496ba7bSLoGin ProcessManager::current_pcb().pid() 5161496ba7bSLoGin ); 517676b8ef6SMork return Err(SystemError::ENOMEM); 518c2481452Shoumkh } 519c2481452Shoumkh } 520c2481452Shoumkh } 521c2481452Shoumkh 522c2481452Shoumkh /// @brief 取消mmio的映射并将地址空间归还到buddy中 523c2481452Shoumkh /// 524c2481452Shoumkh /// @param vaddr 起始的虚拟地址 525c2481452Shoumkh /// 526c2481452Shoumkh /// @param length 要归还的地址空间的长度 527c2481452Shoumkh /// 528c2481452Shoumkh /// @return Ok(i32) 成功返回0 529c2481452Shoumkh /// 530676b8ef6SMork /// @return Err(SystemError) 失败返回错误码 5317eda31b2SLoGin pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> { 53240fe15e0SLoGin assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); 53340fe15e0SLoGin assert!(length & (MMArch::PAGE_SIZE - 1) == 0); 53440fe15e0SLoGin if vaddr < self.pool_start_addr 53540fe15e0SLoGin || vaddr.data() >= self.pool_start_addr.data() + self.pool_size 53640fe15e0SLoGin { 537676b8ef6SMork return Err(SystemError::EINVAL); 538c2481452Shoumkh } 53940fe15e0SLoGin // todo: 重构MMIO管理机制,创建类似全局的manager之类的,管理MMIO的空间? 54040fe15e0SLoGin 54140fe15e0SLoGin // 暂时认为传入的vaddr都是正确的 54240fe15e0SLoGin let page_count = length / MMArch::PAGE_SIZE; 54340fe15e0SLoGin // 取消映射 54440fe15e0SLoGin let mut bindings = KernelMapper::lock(); 54540fe15e0SLoGin let mut kernel_mapper = bindings.as_mut(); 54640fe15e0SLoGin if kernel_mapper.is_none() { 5472eab6dd7S曾俊 warn!("release_mmio: kernel_mapper is read only"); 54840fe15e0SLoGin return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); 549c2481452Shoumkh } 55040fe15e0SLoGin 55140fe15e0SLoGin for i in 0..page_count { 552c2481452Shoumkh unsafe { 5537ae679ddSLoGin let x: Option<( 5547ae679ddSLoGin PhysAddr, 5557ae679ddSLoGin PageFlags<MMArch>, 5567ae679ddSLoGin crate::mm::page::PageFlush<MMArch>, 5577ae679ddSLoGin )> = kernel_mapper 55840fe15e0SLoGin .as_mut() 55940fe15e0SLoGin .unwrap() 5607ae679ddSLoGin .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, false); 5617ae679ddSLoGin if let Some((_, _, flush)) = x { 5627ae679ddSLoGin flush.flush(); 5637ae679ddSLoGin } 56440fe15e0SLoGin }; 565c2481452Shoumkh } 56640fe15e0SLoGin 5677ae679ddSLoGin // 归还到buddy 5687ae679ddSLoGin mmio_pool() 569b5b571e0SLoGin .give_back_block(vaddr, length.trailing_zeros()) 5707ae679ddSLoGin .unwrap_or_else(|err| { 5717ae679ddSLoGin panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err); 5727ae679ddSLoGin }); 57340fe15e0SLoGin 574a7eb62a4Shoumkh return Ok(0); 575a7eb62a4Shoumkh } 576a7eb62a4Shoumkh } 577a7eb62a4Shoumkh 578a7eb62a4Shoumkh /// @brief mmio伙伴系统内部的地址区域结构体 57940fe15e0SLoGin #[derive(Debug, Clone)] 58040fe15e0SLoGin struct MmioBuddyAddrRegion { 58140fe15e0SLoGin vaddr: VirtAddr, 582a7eb62a4Shoumkh } 583a7eb62a4Shoumkh impl MmioBuddyAddrRegion { 58440fe15e0SLoGin pub fn new(vaddr: VirtAddr) -> Self { 58540fe15e0SLoGin return MmioBuddyAddrRegion { vaddr }; 586a7eb62a4Shoumkh } 58740fe15e0SLoGin 58840fe15e0SLoGin #[allow(dead_code)] 58940fe15e0SLoGin pub fn vaddr(&self) -> VirtAddr { 59040fe15e0SLoGin return self.vaddr; 591a7eb62a4Shoumkh } 592a7eb62a4Shoumkh } 593a7eb62a4Shoumkh 594a7eb62a4Shoumkh /// @brief 空闲页数组结构体 595b5b571e0SLoGin #[derive(Debug, Default)] 596a7eb62a4Shoumkh pub struct MmioFreeRegionList { 597a7eb62a4Shoumkh /// 存储mmio_buddy的地址链表 59840fe15e0SLoGin list: LinkedList<MmioBuddyAddrRegion>, 599a7eb62a4Shoumkh /// 空闲块的数量 600a7eb62a4Shoumkh num_free: i64, 601a7eb62a4Shoumkh } 602a7eb62a4Shoumkh impl MmioFreeRegionList { 60364aea4b3SGou Ngai #[allow(dead_code)] 604a7eb62a4Shoumkh fn new() -> Self { 605a7eb62a4Shoumkh return MmioFreeRegionList { 606a7eb62a4Shoumkh ..Default::default() 607a7eb62a4Shoumkh }; 608a7eb62a4Shoumkh } 609a7eb62a4Shoumkh } 610a7eb62a4Shoumkh 611a7eb62a4Shoumkh /// @brief 将内存对象大小的幂转换成内存池中的数组的下标 612a7eb62a4Shoumkh /// 613a7eb62a4Shoumkh /// @param exp内存大小 614a7eb62a4Shoumkh /// 615a7eb62a4Shoumkh /// @return 内存池数组下标 616a7eb62a4Shoumkh #[inline(always)] 617a7eb62a4Shoumkh fn exp2index(exp: u32) -> usize { 618a7eb62a4Shoumkh return (exp - 12) as usize; 619a7eb62a4Shoumkh } 620a7eb62a4Shoumkh 6212dd9f0c7SLoGin #[derive(Debug)] 6222dd9f0c7SLoGin pub struct MMIOSpaceGuard { 6232dd9f0c7SLoGin vaddr: VirtAddr, 6242dd9f0c7SLoGin size: usize, 6252dd9f0c7SLoGin mapped: AtomicBool, 6262dd9f0c7SLoGin } 6272dd9f0c7SLoGin 6282dd9f0c7SLoGin impl MMIOSpaceGuard { 6292dd9f0c7SLoGin pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self { 6302dd9f0c7SLoGin // check size 6312dd9f0c7SLoGin assert!( 6322dd9f0c7SLoGin size & (MMArch::PAGE_SIZE - 1) == 0, 6332dd9f0c7SLoGin "MMIO space size must be page aligned" 6342dd9f0c7SLoGin ); 6352dd9f0c7SLoGin assert!(size.is_power_of_two(), "MMIO space size must be power of 2"); 6362dd9f0c7SLoGin assert!( 6372dd9f0c7SLoGin vaddr.check_aligned(size), 6382dd9f0c7SLoGin "MMIO space vaddr must be aligned with size" 6392dd9f0c7SLoGin ); 6402dd9f0c7SLoGin assert!( 64123ef2b33SLoGin vaddr.data() >= MMArch::MMIO_BASE.data() 64223ef2b33SLoGin && vaddr.data() + size <= MMArch::MMIO_TOP.data(), 6432dd9f0c7SLoGin "MMIO space must be in MMIO region" 6442dd9f0c7SLoGin ); 6452dd9f0c7SLoGin 6462dd9f0c7SLoGin // 人工创建的MMIO空间,认为已经映射 6472dd9f0c7SLoGin MMIOSpaceGuard { 6482dd9f0c7SLoGin vaddr, 6492dd9f0c7SLoGin size, 6502dd9f0c7SLoGin mapped: AtomicBool::new(mapped), 6512dd9f0c7SLoGin } 6522dd9f0c7SLoGin } 6532dd9f0c7SLoGin 6542dd9f0c7SLoGin pub fn vaddr(&self) -> VirtAddr { 6552dd9f0c7SLoGin self.vaddr 6562dd9f0c7SLoGin } 6572dd9f0c7SLoGin 6582dd9f0c7SLoGin pub fn size(&self) -> usize { 6592dd9f0c7SLoGin self.size 6602dd9f0c7SLoGin } 6612dd9f0c7SLoGin 6622dd9f0c7SLoGin /// 将物理地址填写到虚拟地址空间中 6632dd9f0c7SLoGin /// 6642dd9f0c7SLoGin /// ## Safety 6652dd9f0c7SLoGin /// 6662dd9f0c7SLoGin /// 传入的物理地址【一定要是设备的物理地址】。 6672dd9f0c7SLoGin /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。 6687ae679ddSLoGin pub unsafe fn map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError> { 6692dd9f0c7SLoGin if length > self.size { 6707ae679ddSLoGin return Err(SystemError::EINVAL); 6712dd9f0c7SLoGin } 6722dd9f0c7SLoGin 6732dd9f0c7SLoGin let check = self 6742dd9f0c7SLoGin .mapped 6752dd9f0c7SLoGin .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst); 6762dd9f0c7SLoGin if check.is_err() { 6777ae679ddSLoGin return Err(SystemError::EINVAL); 6782dd9f0c7SLoGin } 6792dd9f0c7SLoGin 6802dd9f0c7SLoGin let flags = PageFlags::mmio_flags(); 681731bc2b3SLoGin 6822dd9f0c7SLoGin let mut kernel_mapper = KernelMapper::lock(); 6832dd9f0c7SLoGin let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true); 6847ae679ddSLoGin return r; 6852dd9f0c7SLoGin } 6867ae679ddSLoGin 6870102d69fSLoGin /// # map_any_phys - 将任意物理地址映射到虚拟地址 6880102d69fSLoGin /// 6890102d69fSLoGin /// 将指定的物理地址和长度映射到虚拟地址空间。 6900102d69fSLoGin /// 6910102d69fSLoGin /// ## 参数 6920102d69fSLoGin /// 6930102d69fSLoGin /// - `paddr`: 物理地址,需要被映射的起始地址。 6940102d69fSLoGin /// - `length`: 要映射的物理地址长度。 6950102d69fSLoGin /// 6960102d69fSLoGin /// ## 返回值 6970102d69fSLoGin /// - `Ok(VirtAddr)`: 映射成功,返回虚拟地址的起始地址。 6980102d69fSLoGin /// - `Err(SystemError)`: 映射失败,返回系统错误。 6990102d69fSLoGin /// 7000102d69fSLoGin /// ## 副作用 7010102d69fSLoGin /// 7020102d69fSLoGin /// 该函数会修改虚拟地址空间,将物理地址映射到虚拟地址。 7030102d69fSLoGin /// 7040102d69fSLoGin /// ## Safety 7050102d69fSLoGin /// 7060102d69fSLoGin /// 由于该函数涉及到内存操作,因此它是非安全的。确保在调用该函数时,你传入的物理地址是正确的。 7070102d69fSLoGin #[allow(dead_code)] 7080102d69fSLoGin pub unsafe fn map_any_phys( 7090102d69fSLoGin &self, 7100102d69fSLoGin paddr: PhysAddr, 7110102d69fSLoGin length: usize, 7120102d69fSLoGin ) -> Result<VirtAddr, SystemError> { 7130102d69fSLoGin let paddr_base = PhysAddr::new(page_align_down(paddr.data())); 7140102d69fSLoGin let offset = paddr - paddr_base; 7150102d69fSLoGin let vaddr_base = self.vaddr; 7160102d69fSLoGin let vaddr = vaddr_base + offset; 7170102d69fSLoGin 7180102d69fSLoGin self.map_phys(paddr_base, page_align_up(length + offset))?; 7190102d69fSLoGin return Ok(vaddr); 7200102d69fSLoGin } 7210102d69fSLoGin 7227ae679ddSLoGin /// 泄露一个MMIO space guard,不会释放映射的空间 7237ae679ddSLoGin pub unsafe fn leak(self) { 7247ae679ddSLoGin core::mem::forget(self); 7252dd9f0c7SLoGin } 7262dd9f0c7SLoGin } 7272dd9f0c7SLoGin 7282dd9f0c7SLoGin impl Drop for MMIOSpaceGuard { 7292dd9f0c7SLoGin fn drop(&mut self) { 7302dd9f0c7SLoGin let _ = mmio_pool() 7312dd9f0c7SLoGin .release_mmio(self.vaddr, self.size) 7322dd9f0c7SLoGin .unwrap_or_else(|err| { 7332dd9f0c7SLoGin panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err); 7342dd9f0c7SLoGin }); 7352dd9f0c7SLoGin } 7362dd9f0c7SLoGin } 7372dd9f0c7SLoGin 73840fe15e0SLoGin pub fn mmio_init() { 7392eab6dd7S曾俊 debug!("Initializing MMIO buddy memory pool..."); 74040fe15e0SLoGin // 初始化mmio内存池 74140fe15e0SLoGin unsafe { 74240fe15e0SLoGin __MMIO_POOL = Some(MmioBuddyMemPool::new()); 74340fe15e0SLoGin } 74440fe15e0SLoGin 7452eab6dd7S曾俊 info!("MMIO buddy memory pool init done"); 74640fe15e0SLoGin } 747