新的内存管理模块 (#301)

  实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。

  内存管理模块主要由以下类型的组件组成:

- **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行
- **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中)
- **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新)
- **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator
- **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成)
- **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构)
- **用户地址空间管理机制** - 提供对用户地址空间的管理。
    - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作
    - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射
- **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等
- **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。


除上面的新增内容以外,其它的更改内容:
- 新增二进制加载器,以及elf的解析器
- 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。
- 解决local_irq_save未关中断的错误。
- 修复sys_gettimeofday对timezone参数的处理的bug
This commit is contained in:
LoGin
2023-07-22 16:22:17 +08:00
committed by GitHub
parent 0663027b11
commit d8ad0a5e77
124 changed files with 8277 additions and 5150 deletions

View File

@ -1,16 +1,19 @@
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::mm::kernel_mapper::KernelMapper;
use crate::syscall::SystemError;
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
initial_mm, mm_create_vma, mm_unmap, vm_area_del, vm_area_free, vm_area_struct, vm_flags_t,
vma_find, MMIO_BASE, MMIO_TOP, PAGE_1G_SHIFT, PAGE_1G_SIZE, PAGE_2M_SIZE, PAGE_4K_SHIFT,
PAGE_4K_SIZE, VM_DONTCOPY, VM_IO,
},
kdebug, kerror,
include::bindings::bindings::{vm_flags_t, PAGE_1G_SHIFT, PAGE_4K_SHIFT, PAGE_4K_SIZE},
kdebug,
mm::{MMArch, MemoryManagementArch},
};
use alloc::{boxed::Box, collections::LinkedList, vec::Vec};
use core::{mem, ptr::null_mut};
use crate::{kerror, kinfo, kwarn};
use alloc::{collections::LinkedList, vec::Vec};
use core::mem;
use core::mem::MaybeUninit;
use core::sync::atomic::{compiler_fence, Ordering};
use super::VirtAddr;
// 最大的伙伴块的幂
const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT;
@ -19,8 +22,15 @@ const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT;
// 内存池数组的范围
const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
lazy_static! {
pub static ref MMIO_POOL: MmioBuddyMemPool = MmioBuddyMemPool::new();
const MMIO_BASE: VirtAddr = VirtAddr::new(0xffffa10000000000);
const MMIO_TOP: VirtAddr = VirtAddr::new(0xffffa20000000000);
const PAGE_1G_SIZE: usize = 1 << 30;
static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
pub fn mmio_pool() -> &'static mut MmioBuddyMemPool {
unsafe { __MMIO_POOL.as_mut().unwrap() }
}
pub enum MmioResult {
@ -32,25 +42,49 @@ pub enum MmioResult {
}
/// @brief buddy内存池
#[derive(Debug)]
pub struct MmioBuddyMemPool {
pool_start_addr: u64,
pool_size: u64,
pool_start_addr: VirtAddr,
pool_size: usize,
free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
}
impl Default for MmioBuddyMemPool {
fn default() -> Self {
MmioBuddyMemPool {
pool_start_addr: MMIO_BASE as u64,
pool_size: (MMIO_TOP - MMIO_BASE) as u64,
free_regions: unsafe { mem::zeroed() },
}
}
}
impl MmioBuddyMemPool {
fn new() -> Self {
return MmioBuddyMemPool {
..Default::default()
let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
for i in 0..MMIO_BUDDY_REGION_COUNT {
free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
}
let free_regions = unsafe {
mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
free_regions,
)
};
let pool = MmioBuddyMemPool {
pool_start_addr: MMIO_BASE,
pool_size: MMIO_TOP - MMIO_BASE,
free_regions,
};
kdebug!("MMIO buddy pool init: created");
let cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) >> 30;
let mut vaddr_base = MMIO_BASE;
kdebug!("total 1G blocks: {cnt_1g_blocks}");
for _i in 0..cnt_1g_blocks {
compiler_fence(Ordering::SeqCst);
match pool.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
Ok(_) => {
vaddr_base += PAGE_1G_SIZE;
}
Err(_) => {
panic!("MMIO buddy pool init failed");
}
}
}
kdebug!("MMIO buddy pool init success");
return pool;
}
/// @brief 创建新的地址区域结构体
@ -58,9 +92,12 @@ impl MmioBuddyMemPool {
/// @param vaddr 虚拟地址
///
/// @return 创建好的地址区域结构体
fn create_region(&self, vaddr: u64) -> Box<MmioBuddyAddrRegion> {
let mut region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion::new());
region.vaddr = vaddr;
fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
// kdebug!("create_region for vaddr: {vaddr:?}");
let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
// kdebug!("create_region for vaddr: {vaddr:?} OK!!!");
return region;
}
@ -75,16 +112,16 @@ impl MmioBuddyMemPool {
/// @return Ok(i32) 返回0
///
/// @return Err(SystemError) 返回错误码
fn give_back_block(&self, vaddr: u64, exp: u32) -> Result<i32, SystemError> {
fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
// 确保内存对齐低位都要为0
if (vaddr & ((1 << exp) - 1)) != 0 {
if (vaddr.data() & ((1 << exp) - 1)) != 0 {
return Err(SystemError::EINVAL);
}
let region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr);
let region: MmioBuddyAddrRegion = self.create_region(vaddr);
// 加入buddy
let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
&mut self.free_regions[exp2index(exp)].lock();
self.push_block(region, list_guard);
let mut list_guard = self.free_regions[exp2index(exp)].lock();
self.push_block(region, &mut list_guard);
return Ok(0);
}
@ -97,12 +134,12 @@ impl MmioBuddyMemPool {
/// @param list_guard 【exp-1】对应的链表
fn split_block(
&self,
region: Box<MmioBuddyAddrRegion>,
region: MmioBuddyAddrRegion,
exp: u32,
low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
let vaddr: u64 = self.calculate_block_vaddr(region.vaddr, exp - 1);
let new_region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr);
let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
self.push_block(region, low_list_guard);
self.push_block(new_region, low_list_guard);
}
@ -113,7 +150,7 @@ impl MmioBuddyMemPool {
///
/// @param list_guard exp对应的链表
///
/// @return Ok(Box<MmioBuddyAddrRegion>) 符合要求的内存区域。
/// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
///
/// @return Err(MmioResult)
/// - 没有满足要求的内存块时返回ENOFOUND
@ -123,7 +160,7 @@ impl MmioBuddyMemPool {
&self,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
) -> Result<MmioBuddyAddrRegion, MmioResult> {
// 申请范围错误
if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP {
kdebug!("query_addr_region: exp wrong");
@ -256,12 +293,9 @@ impl MmioBuddyMemPool {
///
/// @param exp 内存区域的大小(2^exp)
///
/// @return Ok(Box<MmioBuddyAddrRegion>)符合要求的内存块信息结构体。
/// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
/// @return Err(MmioResult) 没有满足要求的内存块时返回__query_addr_region的错误码。
fn mmio_buddy_query_addr_region(
&self,
exp: u32,
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
&mut self.free_regions[exp2index(exp)].lock();
match self.query_addr_region(exp, list_guard) {
@ -279,7 +313,7 @@ impl MmioBuddyMemPool {
/// @param list_guard 目标链表
fn push_block(
&self,
region: Box<MmioBuddyAddrRegion>,
region: MmioBuddyAddrRegion,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
list_guard.list.push_back(region);
@ -288,8 +322,8 @@ impl MmioBuddyMemPool {
/// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
#[inline(always)]
fn calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 {
return vaddr ^ (1 << exp);
fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
}
/// @brief 寻找并弹出指定内存块的伙伴块
@ -306,10 +340,10 @@ impl MmioBuddyMemPool {
/// - 没有找到伙伴块返回ENOFOUND
fn pop_buddy_block(
&self,
vaddr: u64,
vaddr: VirtAddr,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
) -> Result<MmioBuddyAddrRegion, MmioResult> {
if list_guard.list.len() == 0 {
return Err(MmioResult::ISEMPTY);
} else {
@ -317,7 +351,7 @@ impl MmioBuddyMemPool {
let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
// element 只会有一个元素
let mut element: Vec<Box<MmioBuddyAddrRegion>> = list_guard
let mut element: Vec<MmioBuddyAddrRegion> = list_guard
.list
.drain_filter(|x| x.vaddr == buddy_vaddr)
.collect();
@ -335,13 +369,13 @@ impl MmioBuddyMemPool {
///
/// @param list_guard 【exp】对应的链表
///
/// @return Ok(Box<MmioBuddyAddrRegion>) 内存块信息结构体的引用。
/// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
///
/// @return Err(MmioResult) 当链表为空无法删除时返回ISEMPTY
fn pop_block(
&self,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
) -> Result<MmioBuddyAddrRegion, MmioResult> {
if !list_guard.list.is_empty() {
list_guard.num_free -= 1;
return Ok(list_guard.list.pop_back().unwrap());
@ -377,17 +411,15 @@ impl MmioBuddyMemPool {
break;
}
// 获取内存块
let vaddr: u64 = list_guard.list.back().unwrap().vaddr;
let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
// 获取伙伴内存块
match self.pop_buddy_block(vaddr, exp, list_guard) {
Err(err) => {
return Err(err);
}
Ok(buddy_region) => {
let region: Box<MmioBuddyAddrRegion> = list_guard.list.pop_back().unwrap();
let copy_region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion {
vaddr: region.vaddr,
});
let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
let copy_region = region.clone();
// 在两块内存都被取出之后才进行合并
match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
Err(err) => {
@ -415,8 +447,8 @@ impl MmioBuddyMemPool {
/// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
fn merge_blocks(
&self,
region_1: Box<MmioBuddyAddrRegion>,
region_2: Box<MmioBuddyAddrRegion>,
region_1: MmioBuddyAddrRegion,
region_2: MmioBuddyAddrRegion,
exp: u32,
high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioResult, MmioResult> {
@ -444,102 +476,43 @@ impl MmioBuddyMemPool {
/// @return Err(SystemError) 失败返回错误码
pub fn create_mmio(
&self,
size: u32,
vm_flags: vm_flags_t,
size: usize,
_vm_flags: vm_flags_t,
res_vaddr: *mut u64,
res_length: *mut u64,
) -> Result<i32, SystemError> {
if size > PAGE_1G_SIZE || size == 0 {
return Err(SystemError::EPERM);
}
let mut retval: i32 = 0;
let retval: i32 = 0;
// 计算前导0
let mut size_exp: u32 = 31 - size.leading_zeros();
#[cfg(target_arch = "x86_64")]
let mut size_exp: u32 = 63 - size.leading_zeros();
// 记录最终申请的空间大小
let mut new_size: u32 = size;
let mut new_size = size;
// 对齐要申请的空间大小
// 如果要申请的空间大小小于4k则分配4k
if size_exp < PAGE_4K_SHIFT {
new_size = PAGE_4K_SIZE;
new_size = PAGE_4K_SIZE as usize;
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) {
match self.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(SystemError::from_posix_errno(retval).unwrap());
}
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(SystemError::from_posix_errno(retval).unwrap());
}
loop_i += PAGE_4K_SIZE as u64;
}
// todo: 是否需要创建vma或者用新重写的机制去做
// kdebug!(
// "create_mmio: vaddr = {:?}, length = {}",
// region.vaddr,
// new_size
// );
unsafe { *res_vaddr = region.vaddr.data() as u64 };
unsafe { *res_length = new_size as u64 };
}
Err(_) => {
kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid);
kerror!("failed to create mmio. pid = {:?}", current_pcb().pid);
return Err(SystemError::ENOMEM);
}
}
@ -555,83 +528,62 @@ impl MmioBuddyMemPool {
/// @return Ok(i32) 成功返回0
///
/// @return Err(SystemError) 失败返回错误码
pub fn release_mmio(&self, vaddr: u64, length: u64) -> Result<i32, SystemError> {
//先将要释放的空间取消映射
unsafe {
mm_unmap(&mut initial_mm, vaddr, length, false);
pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
if vaddr < self.pool_start_addr
|| vaddr.data() >= self.pool_start_addr.data() + self.pool_size
{
return Err(SystemError::EINVAL);
}
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(SystemError::EINVAL);
}
// 检查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(SystemError::EINVAL);
}
// 将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);
}
}
// todo: 重构MMIO管理机制创建类似全局的manager之类的管理MMIO的空间
// 暂时认为传入的vaddr都是正确的
let page_count = length / MMArch::PAGE_SIZE;
// 取消映射
let mut bindings = KernelMapper::lock();
let mut kernel_mapper = bindings.as_mut();
if kernel_mapper.is_none() {
kwarn!("release_mmio: kernel_mapper is read only");
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
for i in 0..page_count {
unsafe {
kernel_mapper
.as_mut()
.unwrap()
.unmap(vaddr + i * MMArch::PAGE_SIZE, true)
};
}
// todo: 归还到buddy
return Ok(0);
}
}
/// @brief mmio伙伴系统内部的地址区域结构体
pub struct MmioBuddyAddrRegion {
vaddr: u64,
#[derive(Debug, Clone)]
struct MmioBuddyAddrRegion {
vaddr: VirtAddr,
}
impl MmioBuddyAddrRegion {
pub fn new() -> Self {
return MmioBuddyAddrRegion {
..Default::default()
};
pub fn new(vaddr: VirtAddr) -> Self {
return MmioBuddyAddrRegion { vaddr };
}
}
impl Default for MmioBuddyAddrRegion {
fn default() -> Self {
MmioBuddyAddrRegion {
vaddr: Default::default(),
}
#[allow(dead_code)]
pub fn vaddr(&self) -> VirtAddr {
return self.vaddr;
}
}
/// @brief 空闲页数组结构体
#[derive(Debug)]
pub struct MmioFreeRegionList {
/// 存储mmio_buddy的地址链表
list: LinkedList<Box<MmioBuddyAddrRegion>>,
list: LinkedList<MmioBuddyAddrRegion>,
/// 空闲块的数量
num_free: i64,
}
@ -652,25 +604,6 @@ impl Default for MmioFreeRegionList {
}
}
/// @brief 初始化mmio的伙伴系统
#[no_mangle]
pub extern "C" fn __mmio_buddy_init() {
// 创建一堆1GB的地址块
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) {
Ok(_) => {
vaddr_base += PAGE_1G_SIZE as u64;
}
Err(_) => {
kerror!("__mmio_buddy_init failed");
return;
}
}
}
}
/// @brief 将内存对象大小的幂转换成内存池中的数组的下标
///
/// @param exp内存大小
@ -681,6 +614,15 @@ fn exp2index(exp: u32) -> usize {
return (exp - 12) as usize;
}
pub fn mmio_init() {
kdebug!("Initializing MMIO buddy memory pool...");
// 初始化mmio内存池
unsafe {
__MMIO_POOL = Some(MmioBuddyMemPool::new());
}
kinfo!("MMIO buddy memory pool init done");
}
/// @brief 创建一块mmio区域并将vma绑定到initial_mm
///
/// @param size mmio区域的大小字节
@ -699,7 +641,8 @@ pub extern "C" fn mmio_create(
res_vaddr: *mut u64,
res_length: *mut u64,
) -> i32 {
if let Err(err) = MMIO_POOL.create_mmio(size, vm_flags, res_vaddr, res_length) {
// kdebug!("mmio_create");
if let Err(err) = mmio_pool().create_mmio(size as usize, vm_flags, res_vaddr, res_length) {
return err.to_posix_errno();
} else {
return 0;
@ -717,9 +660,7 @@ pub extern "C" fn mmio_create(
/// @return Err(i32) 失败返回错误码
#[no_mangle]
pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
if let Err(err) = MMIO_POOL.release_mmio(vaddr, length) {
return err.to_posix_errno();
} else {
return 0;
}
return mmio_pool()
.release_mmio(VirtAddr::new(vaddr as usize), length as usize)
.unwrap_or_else(|err| err.to_posix_errno());
}