diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index 0f3ba6dd..4dfeb8ca 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -1,3 +1,4 @@ +use crate::libs::spinlock::{SpinLock, SpinLockGuard}; use crate::{ arch::asm::current::current_pcb, include::bindings::bindings::{ @@ -6,7 +7,6 @@ use crate::{ PAGE_2M_SIZE, PAGE_4K_SHIFT, PAGE_4K_SIZE, VM_DONTCOPY, VM_IO, }, kdebug, kerror, - libs::spinlock::{SpinLock, SpinLockGuard}, }; use alloc::{boxed::Box, collections::LinkedList, vec::Vec}; use core::{mem, ptr::null_mut}; @@ -57,7 +57,7 @@ impl MmioBuddyMemPool { /// @param vaddr 虚拟地址 /// /// @return 创建好的地址区域结构体 - fn __create_region(&self, vaddr: u64) -> Box { + fn create_region(&self, vaddr: u64) -> Box { let mut region: Box = Box::new(MmioBuddyAddrRegion::new()); region.vaddr = vaddr; return region; @@ -74,16 +74,16 @@ impl MmioBuddyMemPool { /// @return Ok(i32) 返回0 /// /// @return Err(i32) 返回错误码 - fn __give_back_block(&self, vaddr: u64, exp: u32) -> Result { + fn give_back_block(&self, vaddr: u64, exp: u32) -> Result { // 确保内存对齐,低位都要为0 if (vaddr & ((1 << exp) - 1)) != 0 { return Err(-(EINVAL as i32)); } - let region: Box = self.__create_region(vaddr); + let region: Box = self.create_region(vaddr); // 加入buddy let list_guard: &mut SpinLockGuard = - &mut self.free_regions[__exp2index(exp)].lock(); - self.__buddy_add_region_obj(region, list_guard); + &mut self.free_regions[exp2index(exp)].lock(); + self.push_block(region, list_guard); return Ok(0); } @@ -94,16 +94,16 @@ impl MmioBuddyMemPool { /// @param exp 要被分割的地址区域的大小的幂 /// /// @param list_guard 【exp-1】对应的链表 - fn __buddy_split( + fn split_block( &self, region: Box, exp: u32, low_list_guard: &mut SpinLockGuard, ) { - let vaddr: u64 = self.__buddy_block_vaddr(region.vaddr, exp - 1); - let new_region: Box = self.__create_region(vaddr); - self.__buddy_add_region_obj(region, low_list_guard); - self.__buddy_add_region_obj(new_region, low_list_guard); + let vaddr: u64 = self.calculate_block_vaddr(region.vaddr, exp - 1); + let new_region: Box = self.create_region(vaddr); + self.push_block(region, low_list_guard); + self.push_block(new_region, low_list_guard); } /// @brief 从buddy中申请一块指定大小的内存区域 @@ -118,14 +118,14 @@ impl MmioBuddyMemPool { /// - 没有满足要求的内存块时,返回ENOFOUND /// - 申请的内存块大小超过合法范围,返回WRONGEXP /// - 调用函数出错时,返回出错函数对应错误码 - fn __query_addr_region( + fn query_addr_region( &self, exp: u32, list_guard: &mut SpinLockGuard, ) -> Result, MmioResult> { // 申请范围错误 if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP { - kdebug!("__query_addr_region: exp wrong"); + kdebug!("query_addr_region: exp wrong"); return Err(MmioResult::WRONGEXP); } // 没有恰好符合要求的内存块 @@ -134,23 +134,21 @@ impl MmioBuddyMemPool { // 找到最小符合申请范围的内存块 // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 { - if self.free_regions[__exp2index(e) as usize].lock().num_free == 0 { + if self.free_regions[exp2index(e) as usize].lock().num_free == 0 { continue; } for e2 in (exp + 1..e + 1).rev() { - match self - .__buddy_pop_region(&mut self.free_regions[__exp2index(e2) as usize].lock()) - { + match self.pop_block(&mut self.free_regions[exp2index(e2) as usize].lock()) { Ok(region) => { if e2 != exp + 1 { // 要将分裂后的内存块插入到更小的链表中 let low_list_guard: &mut SpinLockGuard = - &mut self.free_regions[__exp2index(e2 - 1) as usize].lock(); - self.__buddy_split(region, e2, low_list_guard); + &mut self.free_regions[exp2index(e2 - 1) as usize].lock(); + self.split_block(region, e2, low_list_guard); } else { // 由于exp对应的链表list_guard已经被锁住了 不能再加锁 // 所以直接将list_guard传入 - self.__buddy_split(region, e2, list_guard); + self.split_block(region, e2, list_guard); } } Err(err) => { @@ -171,10 +169,10 @@ impl MmioBuddyMemPool { for e in MMIO_BUDDY_MIN_EXP..exp { if e != exp - 1 { let high_list_guard: &mut SpinLockGuard = - &mut self.free_regions[__exp2index(exp + 1)].lock(); - match self.__buddy_merge( + &mut self.free_regions[exp2index(exp + 1)].lock(); + match self.merge_all_exp( e, - &mut self.free_regions[__exp2index(e) as usize].lock(), + &mut self.free_regions[exp2index(e) as usize].lock(), high_list_guard, ) { Ok(_) => continue, @@ -183,9 +181,9 @@ impl MmioBuddyMemPool { } } } else { - match self.__buddy_merge( + match self.merge_all_exp( e, - &mut self.free_regions[__exp2index(e) as usize].lock(), + &mut self.free_regions[exp2index(e) as usize].lock(), list_guard, ) { Ok(_) => continue, @@ -217,8 +215,8 @@ impl MmioBuddyMemPool { exp: u32, ) -> Result, MmioResult> { let list_guard: &mut SpinLockGuard = - &mut self.free_regions[__exp2index(exp)].lock(); - match self.__query_addr_region(exp, list_guard) { + &mut self.free_regions[exp2index(exp)].lock(); + match self.query_addr_region(exp, list_guard) { Ok(ret) => return Ok(ret), Err(err) => { kdebug!("mmio_buddy_query_addr_region failed"); @@ -231,7 +229,7 @@ impl MmioBuddyMemPool { /// @param region 要被添加的地址结构体 /// /// @param list_guard 目标链表 - fn __buddy_add_region_obj( + fn push_block( &self, region: Box, list_guard: &mut SpinLockGuard, @@ -242,7 +240,7 @@ impl MmioBuddyMemPool { /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址 #[inline(always)] - fn __buddy_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 { + fn calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 { return vaddr ^ (1 << exp); } @@ -258,7 +256,7 @@ impl MmioBuddyMemPool { /// @return Err(MmioResult) /// - 当链表为空,返回ISEMPTY /// - 没有找到伙伴块,返回ENOFOUND - fn __pop_buddy_block( + fn pop_buddy_block( &self, vaddr: u64, exp: u32, @@ -268,7 +266,7 @@ impl MmioBuddyMemPool { return Err(MmioResult::ISEMPTY); } else { //计算伙伴块的地址 - let buddy_vaddr = self.__buddy_block_vaddr(vaddr, exp); + let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp); // element 只会有一个元素 let mut element: Vec> = list_guard @@ -292,7 +290,7 @@ impl MmioBuddyMemPool { /// @return Ok(Box) 内存块信息结构体的引用。 /// /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY - fn __buddy_pop_region( + fn pop_block( &self, list_guard: &mut SpinLockGuard, ) -> Result, MmioResult> { @@ -314,9 +312,9 @@ impl MmioBuddyMemPool { /// @return Ok(MmioResult) 合并成功返回SUCCESS /// @return Err(MmioResult) /// - 内存块过少,无法合并,返回EINVAL - /// - __pop_buddy_block调用出错,返回其错误码 - /// - __buddy_merge_blocks调用出错,返回其错误码 - fn __buddy_merge( + /// - pop_buddy_block调用出错,返回其错误码 + /// - merge_blocks调用出错,返回其错误码 + fn merge_all_exp( &self, exp: u32, list_guard: &mut SpinLockGuard, @@ -333,7 +331,7 @@ impl MmioBuddyMemPool { // 获取内存块 let vaddr: u64 = list_guard.list.back().unwrap().vaddr; // 获取伙伴内存块 - match self.__pop_buddy_block(vaddr, exp, list_guard) { + match self.pop_buddy_block(vaddr, exp, list_guard) { Err(err) => { return Err(err); } @@ -343,11 +341,11 @@ impl MmioBuddyMemPool { vaddr: region.vaddr, }); // 在两块内存都被取出之后才进行合并 - match self.__buddy_merge_blocks(region, buddy_region, exp, high_list_guard) { + match self.merge_blocks(region, buddy_region, exp, high_list_guard) { Err(err) => { // 如果合并失败了要将取出来的元素放回去 - self.__buddy_add_region_obj(copy_region, list_guard); - kdebug!("__buddy_merge: __buddy_merge_blocks failed"); + self.push_block(copy_region, list_guard); + kdebug!("merge_all_exp: merge_blocks failed"); return Err(err); } Ok(_) => continue, @@ -367,7 +365,7 @@ impl MmioBuddyMemPool { /// @return Ok(MmioResult) 成功返回SUCCESS /// /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL - fn __buddy_merge_blocks( + fn merge_blocks( &self, region_1: Box, region_2: Box, @@ -375,13 +373,192 @@ impl MmioBuddyMemPool { high_list_guard: &mut SpinLockGuard, ) -> Result { // 判断是否为伙伴块 - if region_1.vaddr != self.__buddy_block_vaddr(region_2.vaddr, exp) { + if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) { return Err(MmioResult::EINVAL); } // 将大的块放进下一级链表 - self.__buddy_add_region_obj(region_1, high_list_guard); + self.push_block(region_1, high_list_guard); return Ok(MmioResult::SUCCESS); } + + /// @brief 创建一块mmio区域,并将vma绑定到initial_mm + /// + /// @param size mmio区域的大小(字节) + /// + /// @param vm_flags 要把vma设置成的标志 + /// + /// @param res_vaddr 返回值-分配得到的虚拟地址 + /// + /// @param res_length 返回值-分配的虚拟地址空间长度 + /// + /// @return Ok(i32) 成功返回0 + /// + /// @return Err(i32) 失败返回错误码 + fn create_mmio( + &self, + size: u32, + vm_flags: vm_flags_t, + res_vaddr: *mut u64, + res_length: *mut u64, + ) -> Result { + if size > PAGE_1G_SIZE || size == 0 { + return Err(-(EPERM as i32)); + } + let mut retval: i32 = 0; + // 计算前导0 + let mut size_exp: u32 = 31 - size.leading_zeros(); + // 记录最终申请的空间大小 + let mut new_size: u32 = size; + // 对齐要申请的空间大小 + // 如果要申请的空间大小小于4k,则分配4k + if size_exp < PAGE_4K_SHIFT { + new_size = PAGE_4K_SIZE; + size_exp = PAGE_4K_SHIFT; + } else if (new_size & (!(1 << size_exp))) != 0 { + // 向左对齐空间大小 + size_exp += 1; + new_size = 1 << size_exp; + } + match MMIO_POOL.mmio_buddy_query_addr_region(size_exp) { + Ok(region) => { + unsafe { + *res_vaddr = region.vaddr; + *res_length = new_size as u64; + } + // 创建vma + let flags: u64 = vm_flags | (VM_IO | VM_DONTCOPY) as u64; + let len_4k: u64 = (new_size % PAGE_2M_SIZE) as u64; + let len_2m: u64 = new_size as u64 - len_4k; + let mut loop_i: u64 = 0; + // 先分配2M的vma + loop { + if loop_i >= len_2m { + break; + } + let vma: *mut *mut vm_area_struct = null_mut(); + retval = unsafe { + mm_create_vma( + &mut initial_mm, + region.vaddr + loop_i, + PAGE_2M_SIZE.into(), + flags, + null_mut(), + vma, + ) + }; + if retval != 0 { + kdebug!( + "failed to create mmio 2m vma. pid = {:?}", + current_pcb().pid + ); + unsafe { + vm_area_del(*vma); + vm_area_free(*vma); + } + return Err(retval); + } + loop_i += PAGE_2M_SIZE as u64; + } + // 分配4K的vma + loop_i = len_2m; + loop { + if loop_i >= size as u64 { + break; + } + let vma: *mut *mut vm_area_struct = null_mut(); + retval = unsafe { + mm_create_vma( + &mut initial_mm, + region.vaddr + loop_i, + PAGE_4K_SIZE.into(), + flags, + null_mut(), + vma, + ) + }; + if retval != 0 { + kdebug!( + "failed to create mmio 4k vma. pid = {:?}", + current_pcb().pid + ); + unsafe { + vm_area_del(*vma); + vm_area_free(*vma); + } + return Err(retval); + } + loop_i += PAGE_4K_SIZE as u64; + } + } + Err(_) => { + kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid); + return Err(-(ENOMEM as i32)); + } + } + return Ok(retval); + } + + /// @brief 取消mmio的映射并将地址空间归还到buddy中 + /// + /// @param vaddr 起始的虚拟地址 + /// + /// @param length 要归还的地址空间的长度 + /// + /// @return Ok(i32) 成功返回0 + /// + /// @return Err(i32) 失败返回错误码 + fn release_mmio(&self, vaddr: u64, length: u64) -> Result { + //先将要释放的空间取消映射 + unsafe { + mm_unmap(&mut initial_mm, vaddr, length, false); + } + let mut loop_i: u64 = 0; + loop { + if loop_i >= length { + break; + } + // 获取要释放的vma的结构体 + let vma: *mut vm_area_struct = unsafe { vma_find(&mut initial_mm, vaddr + loop_i) }; + if vma == null_mut() { + kdebug!( + "mmio_release failed: vma not found. At address: {:?}, pid = {:?}", + vaddr + loop_i, + current_pcb().pid + ); + return Err(-(EINVAL as i32)); + } + // 检查vma起始地址是否正确 + if unsafe { (*vma).vm_start != (vaddr + loop_i) } { + kdebug!( + "mmio_release failed: addr_start is not equal to current: {:?}. pid = {:?}", + vaddr + loop_i, + current_pcb().pid + ); + return Err(-(EINVAL as i32)); + } + // 将vma对应空间归还 + match MMIO_POOL.give_back_block(unsafe { (*vma).vm_start }, unsafe { + 31 - ((*vma).vm_end - (*vma).vm_start).leading_zeros() + }) { + Ok(_) => { + loop_i += unsafe { (*vma).vm_end - (*vma).vm_start }; + unsafe { + vm_area_del(vma); + vm_area_free(vma); + } + } + Err(err) => { + // vma对应空间没有成功归还的话,就不删除vma + kdebug!( + "mmio_release give_back failed: pid = {:?}", + current_pcb().pid + ); + return Err(err); + } + } + } + return Ok(0); + } } /// @brief mmio伙伴系统内部的地址区域结构体 @@ -433,7 +610,7 @@ pub extern "C" fn __mmio_buddy_init() { let cnt_1g_blocks: u32 = ((MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE as i64) as u32; let mut vaddr_base: u64 = MMIO_BASE as u64; for _ in 0..cnt_1g_blocks { - match MMIO_POOL.__give_back_block(vaddr_base, PAGE_1G_SHIFT) { + match MMIO_POOL.give_back_block(vaddr_base, PAGE_1G_SHIFT) { Ok(_) => { vaddr_base += PAGE_1G_SIZE as u64; } @@ -451,7 +628,7 @@ pub extern "C" fn __mmio_buddy_init() { /// /// @return 内存池数组下标 #[inline(always)] -fn __exp2index(exp: u32) -> usize { +fn exp2index(exp: u32) -> usize { return (exp - 12) as usize; } @@ -473,101 +650,11 @@ pub extern "C" fn mmio_create( res_vaddr: *mut u64, res_length: *mut u64, ) -> i32 { - if size > PAGE_1G_SIZE || size == 0 { - return -(EPERM as i32); + if let Err(err) = MMIO_POOL.create_mmio(size, vm_flags, res_vaddr, res_length) { + return err; + } else { + return 0; } - let mut retval: i32 = 0; - // 计算前导0 - let mut size_exp: u32 = 31 - size.leading_zeros(); - // 记录最终申请的空间大小 - let mut new_size: u32 = size; - // 对齐要申请的空间大小 - // 如果要申请的空间大小小于4k,则分配4k - if size_exp < PAGE_4K_SHIFT { - new_size = PAGE_4K_SIZE; - size_exp = PAGE_4K_SHIFT; - } else if (new_size & (!(1 << size_exp))) != 0 { - // 向左对齐空间大小 - size_exp += 1; - new_size = 1 << size_exp; - } - match MMIO_POOL.mmio_buddy_query_addr_region(size_exp) { - Ok(region) => { - unsafe { - *res_vaddr = region.vaddr; - *res_length = new_size as u64; - } - // 创建vma - let flags: u64 = vm_flags | (VM_IO | VM_DONTCOPY) as u64; - let len_4k: u64 = (new_size % PAGE_2M_SIZE) as u64; - let len_2m: u64 = new_size as u64 - len_4k; - let mut loop_i: u64 = 0; - // 先分配2M的vma - loop { - if loop_i >= len_2m { - break; - } - let vma: *mut *mut vm_area_struct = null_mut(); - retval = unsafe { - mm_create_vma( - &mut initial_mm, - region.vaddr + loop_i, - PAGE_2M_SIZE.into(), - flags, - null_mut(), - vma, - ) - }; - if retval != 0 { - kdebug!( - "failed to create mmio 2m vma. pid = {:?}", - current_pcb().pid - ); - unsafe { - vm_area_del(*vma); - vm_area_free(*vma); - } - return retval; - } - loop_i += PAGE_2M_SIZE as u64; - } - // 分配4K的vma - loop_i = len_2m; - loop { - if loop_i >= size as u64 { - break; - } - let vma: *mut *mut vm_area_struct = null_mut(); - retval = unsafe { - mm_create_vma( - &mut initial_mm, - region.vaddr + loop_i, - PAGE_4K_SIZE.into(), - flags, - null_mut(), - vma, - ) - }; - if retval != 0 { - kdebug!( - "failed to create mmio 4k vma. pid = {:?}", - current_pcb().pid - ); - unsafe { - vm_area_del(*vma); - vm_area_free(*vma); - } - return retval; - } - loop_i += PAGE_4K_SIZE as u64; - } - } - Err(_) => { - kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid); - return -(ENOMEM as i32); - } - } - return retval; } /// @brief 取消mmio的映射并将地址空间归还到buddy中 @@ -581,54 +668,9 @@ pub extern "C" fn mmio_create( /// @return Err(i32) 失败返回错误码 #[no_mangle] pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 { - //先将要释放的空间取消映射 - unsafe { - mm_unmap(&mut initial_mm, vaddr, length, false); + if let Err(err) = MMIO_POOL.release_mmio(vaddr, length) { + return err; + } else { + return 0; } - let mut loop_i: u64 = 0; - loop { - if loop_i >= length { - break; - } - // 获取要释放的vma的结构体 - let vma: *mut vm_area_struct = unsafe { vma_find(&mut initial_mm, vaddr + loop_i) }; - if vma == null_mut() { - kdebug!( - "mmio_release failed: vma not found. At address: {:?}, pid = {:?}", - vaddr + loop_i, - current_pcb().pid - ); - return -(EINVAL as i32); - } - // 检查vma起始地址是否正确 - if unsafe { (*vma).vm_start != (vaddr + loop_i) } { - kdebug!( - "mmio_release failed: addr_start is not equal to current: {:?}. pid = {:?}", - vaddr + loop_i, - current_pcb().pid - ); - return -(EINVAL as i32); - } - // 将vma对应空间归还 - match MMIO_POOL.__give_back_block(unsafe { (*vma).vm_start }, unsafe { - 31 - ((*vma).vm_end - (*vma).vm_start).leading_zeros() - }) { - Ok(_) => { - loop_i += unsafe { (*vma).vm_end - (*vma).vm_start }; - unsafe { - vm_area_del(vma); - vm_area_free(vma); - } - } - Err(err) => { - // vma对应空间没有成功归还的话,就不删除vma - kdebug!( - "mmio_release give_back failed: pid = {:?}", - current_pcb().pid - ); - return err; - } - } - } - return 0; }