mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-21 00:06:32 +00:00
新的内存管理模块 (#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:
@ -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());
|
||||
}
|
||||
|
Reference in New Issue
Block a user