Files
DragonOS/kernel/src/mm/mmio_buddy.rs
LoGin 1496ba7b24 进程管理模块重构完成 (#380)
* 添加新版pcb的数据结构 (#273)

* 将pcb中的内容分类,分别加锁 (#305)

* 进程管理重构:完成fork的主体逻辑 (#309)

1.完成fork的主体逻辑
2.将文件系统接到新的pcb上
3.经过思考,暂时弃用signal机制,待进程管理重构完成后,重写signal机制.原因是原本的signal机制太烂了

* chdir getcwd pid pgid ppid (#310)


---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* 删除旧的fork以及signal的代码,并调整fork/vfork/execve系统调用 (#325)

1.删除旧的fork
2.删除signal相关代码,等进程管理重构结束之后,再重新写.
3.调整了fork/vfork/execve系统调用

* 实现切换进程的代码 (#331)



* 实现切换进程的代码

* Patch modify preempt (#332)

* 修改设置preempt的代码

* 删除rust的list和refcount

* 为每个核心初始化idle进程 (#333)

* 为每个核心初始化idle进程

* 完成了新的内核线程机制 (#335)

* 调度器的pcb替换为新的Arc<ProcessControlBlock>,把调度器队列锁从 RwSpinLock 替换为了 SpinLock (#336)

* 把调度器的pcb替换为新的Arc<ProcessControlBlock>

* 把调度器队列锁从 RwSpinLock 替换为了 SpinLock ,修改了签名以通过编译

* 修正一些双重加锁、细节问题

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* github workflow自动检查代码是否格式化

* cache toolchain yml

* 调整rust版本的waitqueue中的pcb为新版的pcb (#343)

* 解决设置rust workspace带来的“工具链不一致”的问题 (#344)


* 解决设置rust workspace带来的“工具链不一致”的问题

更改workflow

* 调整pcb的sched_info和rwlock,以避免调度器死锁问题 (#341)

* 调整pcb的sched_info和rwlock,以避免调度器死锁问题

* 修改为在 WriterGuard 中维护 Irq_guard

* 修正了 write_irqsave方法

* 优化了代码

* 把 set state 操作从 wakup 移动到 sched_enqueue 中

* 修正为在 wakeup 中设置 running ,以保留 set_state 的私有性

* 移除了 process_wakeup

* 实现进程退出的逻辑 (#340)

实现进程退出的逻辑

* 标志进程sleep

* 修复wakeup的问题

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* rust 重构 completion (#350)

* 完成了completion的基本结构,待完善上级调用

* 用SpinLock保护结构体并发安全

* 修改原子变量为u32,修复符号错误

* irq guard

* 修改为具有内部可变性的结构体

* temp fix

* 修复了由于进程持有自旋锁导致的不被调度的问题

* 对 complete 系列方法上锁,保护 done 数据并发安全

* 移除了未使用的依赖

* 重写显示刷新驱动 (#363)

* 重构显示刷新驱动

* Patch refactor process management (#366)

* 维护进程树

* 维护进程树

* 更改代码结构

* 新建进程时,设置cwd

* 调整adopt childern函数,降低开销

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* waitqueue兼容C部分 (#351)

* PATH

* safe init

* waitqueue兼容C部分

* waitqueue兼容C部分

* 删除semaphore.c,在ps2_keyboard中使用waitqueue

* 删除semaphore.c,在ps2_keyboard中使用waitqueue

* current_pcb的C兼容

* current_pcb的C兼容

* current_pcb的C兼容

* fmt

* current_pcb的兼容

* 针对修改

* 调整代码

* fmt

* 删除pcb的set flags

* 更改函数名

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* merge master

* Patch debug process management refactor (#372)

* 能够调通,执行完textui_init

* 能跑到initial kernel thread

* fmt

* 能够正常初始化所有服务(尚未能切换到用户程序)

* 删除部分无用的extern

* 存在问题:ap处理器启动后,bsp的smp_init函数return之后就出错了,怀疑是栈损坏

* 解决smp启动由于未换栈导致的内存访问错误

* debug

* 1

* 1

* lock no preempt

* 调通

* 优化代码,删除一些调试日志

* fix

* 使用rust重写wait4 (#377)

* 维护进程树

* 维护进程树

* 更改代码结构

* 新建进程时,设置cwd

* 调整adopt childern函数,降低开销

* wait4

* 删除c_sys_wait4

* 使用userbuffer保护裸指针

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* 消除warning

* 1. 修正未设置cpu executing的问题

* 修正kthread机制可能存在的内存泄露问题

* 删除pcb文档

* 删除C的tss struct

---------

Co-authored-by: Bullet <93781792+GP-Bullet@users.noreply.github.com>
Co-authored-by: Chiichen <39649411+Chiichen@users.noreply.github.com>
Co-authored-by: hanjiezhou <zhouhanjie@dragonos.org>
Co-authored-by: GnoCiYeH <118462160+GnoCiYeH@users.noreply.github.com>
Co-authored-by: houmkh <1119644616@qq.com>
2023-09-15 14:58:19 +08:00

746 lines
25 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::mm::kernel_mapper::KernelMapper;
use crate::process::ProcessManager;
use crate::syscall::SystemError;
use crate::{
include::bindings::bindings::{vm_flags_t, PAGE_1G_SHIFT, PAGE_4K_SHIFT, PAGE_4K_SIZE},
kdebug,
mm::{MMArch, MemoryManagementArch},
};
use crate::{kerror, kinfo, kwarn};
use alloc::{collections::LinkedList, vec::Vec};
use core::mem;
use core::mem::MaybeUninit;
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use super::page::PageFlags;
use super::{PhysAddr, VirtAddr};
// 最大的伙伴块的幂
const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT;
// 最小的伙伴块的幂
const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT;
// 内存池数组的范围
const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
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 {
SUCCESS,
EINVAL,
ENOFOUND,
WRONGEXP,
ISEMPTY,
}
/// @brief buddy内存池
#[derive(Debug)]
pub struct MmioBuddyMemPool {
pool_start_addr: VirtAddr,
pool_size: usize,
free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
}
impl MmioBuddyMemPool {
fn new() -> Self {
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 创建新的地址区域结构体
///
/// @param vaddr 虚拟地址
///
/// @return 创建好的地址区域结构体
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;
}
/// @brief 将内存块归还给buddy
///
/// @param vaddr 虚拟地址
///
/// @param exp 内存空间的大小2^exp
///
/// @param list_guard 【exp】对应的链表
///
/// @return Ok(i32) 返回0
///
/// @return Err(SystemError) 返回错误码
fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
// 确保内存对齐低位都要为0
if (vaddr.data() & ((1 << exp) - 1)) != 0 {
return Err(SystemError::EINVAL);
}
let region: MmioBuddyAddrRegion = self.create_region(vaddr);
// 加入buddy
let mut list_guard = self.free_regions[exp2index(exp)].lock();
self.push_block(region, &mut list_guard);
return Ok(0);
}
/// @brief 将给定大小为2^{exp}的内存块一分为二并插入内存块大小为2^{exp-1}的链表中
///
/// @param region 要被分割的地址区域结构体(保证其已经从链表中取出)
///
/// @param exp 要被分割的地址区域的大小的幂
///
/// @param list_guard 【exp-1】对应的链表
fn split_block(
&self,
region: MmioBuddyAddrRegion,
exp: u32,
low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
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);
}
/// @brief 从buddy中申请一块指定大小的内存区域
///
/// @param exp 要申请的内存块的大小的幂(2^exp)
///
/// @param list_guard exp对应的链表
///
/// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
///
/// @return Err(MmioResult)
/// - 没有满足要求的内存块时返回ENOFOUND
/// - 申请的内存块大小超过合法范围返回WRONGEXP
/// - 调用函数出错时,返回出错函数对应错误码
fn query_addr_region(
&self,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
// 申请范围错误
if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP {
kdebug!("query_addr_region: exp wrong");
return Err(MmioResult::WRONGEXP);
}
// 没有恰好符合要求的内存块
// 注意exp对应的链表list_guard已上锁【注意避免死锁问题】
if list_guard.num_free == 0 {
// 找到最小符合申请范围的内存块
// 将大的内存块依次分成小块内存直到能够满足exp大小即将exp+1分成两块exp
for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 {
let pop_list: &mut SpinLockGuard<MmioFreeRegionList> =
&mut self.free_regions[exp2index(e) as usize].lock();
if pop_list.num_free == 0 {
continue;
}
for e2 in (exp + 1..e + 1).rev() {
if e2 == e {
match self.pop_block(pop_list) {
Ok(region) => {
if e2 != exp + 1 {
// 要将分裂后的内存块插入到更小的链表中
let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
&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.split_block(region, e2, list_guard);
}
}
Err(err) => {
kdebug!("buddy_pop_region get wrong");
return Err(err);
}
}
} else {
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<MmioFreeRegionList> =
&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.split_block(region, e2, list_guard);
}
}
Err(err) => {
kdebug!("buddy_pop_region get wrong");
return Err(err);
}
}
}
}
break;
}
// 判断是否获得了exp大小的内存块
if list_guard.num_free > 0 {
match self.pop_block(list_guard) {
Ok(ret) => return Ok(ret),
Err(err) => return Err(err),
}
}
// 拆分大内存块无法获得exp大小内存块
// 尝试用小内存块合成
// 即将两块exp合成一块exp+1
// TODO修改下一个循环的冗余代码请不要删除此处的注释
// let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| {
// if let Err(err) = self.merge_all_exp(
// exp,
// &mut self.free_regions[exp2index(exp) as usize].lock(),
// high_list_guard,
// ) {
// return err;
// } else {
// return MmioResult::SUCCESS;
// }
// };
for e in MMIO_BUDDY_MIN_EXP..exp {
if e != exp - 1 {
match self.merge_all_exp(
exp,
&mut self.free_regions[exp2index(exp) as usize].lock(),
&mut self.free_regions[exp2index(exp + 1)].lock(),
) {
Ok(_) => continue,
Err(err) => {
kdebug!("merge_all_exp get wrong");
return Err(err);
}
}
} else {
match self.merge_all_exp(
exp,
&mut self.free_regions[exp2index(exp) as usize].lock(),
list_guard,
) {
Ok(_) => continue,
Err(err) => {
kdebug!("merge_all_exp get wrong");
return Err(err);
}
}
}
}
//判断是否获得了exp大小的内存块
if list_guard.num_free > 0 {
match self.pop_block(list_guard) {
Ok(ret) => return Ok(ret),
Err(err) => return Err(err),
}
}
return Err(MmioResult::ENOFOUND);
} else {
match self.pop_block(list_guard) {
Ok(ret) => return Ok(ret),
Err(err) => return Err(err),
}
}
}
/// @brief 对query_addr_region进行封装
///
/// @param exp 内存区域的大小(2^exp)
///
/// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
/// @return Err(MmioResult) 没有满足要求的内存块时返回__query_addr_region的错误码。
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) {
Ok(ret) => return Ok(ret),
Err(err) => {
kdebug!("mmio_buddy_query_addr_region failed");
return Err(err);
}
}
}
/// @brief 往指定的地址空间链表中添加一个地址区域
///
/// @param region 要被添加的地址结构体
///
/// @param list_guard 目标链表
fn push_block(
&self,
region: MmioBuddyAddrRegion,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
list_guard.list.push_back(region);
list_guard.num_free += 1;
}
/// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
#[inline(always)]
fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
}
/// @brief 寻找并弹出指定内存块的伙伴块
///
/// @param region 对应内存块的信息
///
/// @param exp 内存块大小
///
/// @param list_guard 【exp】对应的链表
///
/// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用
/// @return Err(MmioResult)
/// - 当链表为空返回ISEMPTY
/// - 没有找到伙伴块返回ENOFOUND
fn pop_buddy_block(
&self,
vaddr: VirtAddr,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
if list_guard.list.len() == 0 {
return Err(MmioResult::ISEMPTY);
} else {
//计算伙伴块的地址
let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
// element 只会有一个元素
let mut element: Vec<MmioBuddyAddrRegion> = list_guard
.list
.drain_filter(|x| x.vaddr == buddy_vaddr)
.collect();
if element.len() == 1 {
list_guard.num_free -= 1;
return Ok(element.pop().unwrap());
}
//没有找到对应的伙伴块
return Err(MmioResult::ENOFOUND);
}
}
/// @brief 从指定空闲链表中取出内存区域
///
/// @param list_guard 【exp】对应的链表
///
/// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
///
/// @return Err(MmioResult) 当链表为空无法删除时返回ISEMPTY
fn pop_block(
&self,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
if !list_guard.list.is_empty() {
list_guard.num_free -= 1;
return Ok(list_guard.list.pop_back().unwrap());
}
return Err(MmioResult::ISEMPTY);
}
/// @brief 合并所有2^{exp}大小的内存块
///
/// @param exp 内存块大小的幂(2^exp)
///
/// @param list_guard exp对应的链表
///
/// @param high_list_guard exp+1对应的链表
///
/// @return Ok(MmioResult) 合并成功返回SUCCESS
/// @return Err(MmioResult)
/// - 内存块过少无法合并返回EINVAL
/// - pop_buddy_block调用出错返回其错误码
/// - merge_blocks调用出错返回其错误码
fn merge_all_exp(
&self,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioResult, MmioResult> {
// 至少要两个内存块才能合并
if list_guard.num_free <= 1 {
return Err(MmioResult::EINVAL);
}
loop {
if list_guard.num_free <= 1 {
break;
}
// 获取内存块
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: 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) => {
// 如果合并失败了要将取出来的元素放回去
self.push_block(copy_region, list_guard);
kdebug!("merge_all_exp: merge_blocks failed");
return Err(err);
}
Ok(_) => continue,
}
}
}
}
return Ok(MmioResult::SUCCESS);
}
/// @brief 合并两个【已经从链表中取出】的内存块
///
/// @param region_1 第一个内存块
///
/// @param region_2 第二个内存
///
/// @return Ok(MmioResult) 成功返回SUCCESS
///
/// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
fn merge_blocks(
&self,
region_1: MmioBuddyAddrRegion,
region_2: MmioBuddyAddrRegion,
exp: u32,
high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioResult, MmioResult> {
// 判断是否为伙伴块
if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) {
return Err(MmioResult::EINVAL);
}
// 将大的块放进下一级链表
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(SystemError) 失败返回错误码
pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
if size > PAGE_1G_SIZE || size == 0 {
return Err(SystemError::EPERM);
}
// 计算前导0
#[cfg(target_arch = "x86_64")]
let mut size_exp: u32 = 63 - size.leading_zeros();
// 记录最终申请的空间大小
let mut new_size = size;
// 对齐要申请的空间大小
// 如果要申请的空间大小小于4k则分配4k
if size_exp < PAGE_4K_SHIFT {
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 self.mmio_buddy_query_addr_region(size_exp) {
Ok(region) => {
let space_guard =
unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) };
return Ok(space_guard);
}
Err(_) => {
kerror!(
"failed to create mmio. pid = {:?}",
ProcessManager::current_pcb().pid()
);
return Err(SystemError::ENOMEM);
}
}
}
/// @brief 取消mmio的映射并将地址空间归还到buddy中
///
/// @param vaddr 起始的虚拟地址
///
/// @param length 要归还的地址空间的长度
///
/// @return Ok(i32) 成功返回0
///
/// @return Err(SystemError) 失败返回错误码
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);
}
// 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_phys(vaddr + i * MMArch::PAGE_SIZE, true)
};
}
// todo: 归还到buddy
return Ok(0);
}
}
/// @brief mmio伙伴系统内部的地址区域结构体
#[derive(Debug, Clone)]
struct MmioBuddyAddrRegion {
vaddr: VirtAddr,
}
impl MmioBuddyAddrRegion {
pub fn new(vaddr: VirtAddr) -> Self {
return MmioBuddyAddrRegion { vaddr };
}
#[allow(dead_code)]
pub fn vaddr(&self) -> VirtAddr {
return self.vaddr;
}
}
/// @brief 空闲页数组结构体
#[derive(Debug)]
pub struct MmioFreeRegionList {
/// 存储mmio_buddy的地址链表
list: LinkedList<MmioBuddyAddrRegion>,
/// 空闲块的数量
num_free: i64,
}
impl MmioFreeRegionList {
#[allow(dead_code)]
fn new() -> Self {
return MmioFreeRegionList {
..Default::default()
};
}
}
impl Default for MmioFreeRegionList {
fn default() -> Self {
MmioFreeRegionList {
list: Default::default(),
num_free: 0,
}
}
}
/// @brief 将内存对象大小的幂转换成内存池中的数组的下标
///
/// @param exp内存大小
///
/// @return 内存池数组下标
#[inline(always)]
fn exp2index(exp: u32) -> usize {
return (exp - 12) as usize;
}
#[derive(Debug)]
pub struct MMIOSpaceGuard {
vaddr: VirtAddr,
size: usize,
mapped: AtomicBool,
}
impl MMIOSpaceGuard {
pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self {
// check size
assert!(
size & (MMArch::PAGE_SIZE - 1) == 0,
"MMIO space size must be page aligned"
);
assert!(size.is_power_of_two(), "MMIO space size must be power of 2");
assert!(
vaddr.check_aligned(size),
"MMIO space vaddr must be aligned with size"
);
assert!(
vaddr.data() >= MMIO_BASE.data() && vaddr.data() + size <= MMIO_TOP.data(),
"MMIO space must be in MMIO region"
);
// 人工创建的MMIO空间认为已经映射
MMIOSpaceGuard {
vaddr,
size,
mapped: AtomicBool::new(mapped),
}
}
pub fn vaddr(&self) -> VirtAddr {
self.vaddr
}
pub fn size(&self) -> usize {
self.size
}
/// 将物理地址填写到虚拟地址空间中
///
/// ## Safety
///
/// 传入的物理地址【一定要是设备的物理地址】。
/// 如果物理地址是从内存分配器中分配的那么会造成内存泄露。因为mmio_release的时候只取消映射不会释放内存。
pub unsafe fn map_phys<Arch: MemoryManagementArch>(
&self,
paddr: PhysAddr,
length: usize,
) -> bool {
if length > self.size {
return false;
}
let check = self
.mapped
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
if check.is_err() {
return false;
}
let flags = PageFlags::mmio_flags();
let mut kernel_mapper = KernelMapper::lock();
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
if r.is_err() {
return false;
}
return true;
}
}
impl Drop for MMIOSpaceGuard {
fn drop(&mut self) {
let _ = mmio_pool()
.release_mmio(self.vaddr, self.size)
.unwrap_or_else(|err| {
panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err);
});
}
}
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区域的大小字节
///
/// @param vm_flags 要把vma设置成的标志
///
/// @param res_vaddr 返回值-分配得到的虚拟地址
///
/// @param res_length 返回值-分配的虚拟地址空间长度
///
/// @return int 错误码
#[no_mangle]
pub unsafe extern "C" fn mmio_create(
size: u32,
_vm_flags: vm_flags_t,
res_vaddr: *mut u64,
res_length: *mut u64,
) -> i32 {
// kdebug!("mmio_create");
let r = mmio_pool().create_mmio(size as usize);
if r.is_err() {
return r.unwrap_err().to_posix_errno();
}
let space_guard = r.unwrap();
*res_vaddr = space_guard.vaddr().data() as u64;
*res_length = space_guard.size() as u64;
// 由于space_guard drop的时候会自动释放内存所以这里要忽略它的释放
core::mem::forget(space_guard);
return 0;
}
/// @brief 取消mmio的映射并将地址空间归还到buddy中
///
/// @param vaddr 起始的虚拟地址
///
/// @param length 要归还的地址空间的长度
///
/// @return Ok(i32) 成功返回0
///
/// @return Err(i32) 失败返回错误码
#[no_mangle]
pub unsafe extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
return mmio_pool()
.release_mmio(VirtAddr::new(vaddr as usize), length as usize)
.unwrap_or_else(|err| err.to_posix_errno());
}