DragonOS/kernel/src/mm/kernel_mapper.rs
LoGin e28411791f
完成中断管理模块重构 (#554)
- 支持中断共享
- 把现有驱动程序移植到新的irq模块
- 使用`ProcessorId`标识处理器id
- 尚未实现threaded_irq

性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。
2024-03-03 16:31:08 +08:00

151 lines
4.8 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 system_error::SystemError;
use super::{page::PageFlags, PageTableKind, PhysAddr, VirtAddr};
use crate::{
arch::{
mm::{LockedFrameAllocator, PageMapper},
CurrentIrqArch,
},
exception::InterruptArch,
libs::align::page_align_up,
mm::{allocator::page_frame::PageFrameCount, MMArch, MemoryManagementArch},
smp::{
core::smp_get_processor_id,
cpu::{AtomicProcessorId, ProcessorId},
},
};
use core::{
ops::Deref,
sync::atomic::{compiler_fence, AtomicUsize, Ordering},
};
/// 标志当前没有处理器持有内核映射器的锁
/// 之所以需要这个标志,是因为 AtomicProcessorId::new(0) 会把0当作一个处理器的id
const KERNEL_MAPPER_NO_PROCESSOR: ProcessorId = ProcessorId::INVALID;
/// 当前持有内核映射器锁的处理器
static KERNEL_MAPPER_LOCK_OWNER: AtomicProcessorId =
AtomicProcessorId::new(KERNEL_MAPPER_NO_PROCESSOR);
/// 内核映射器的锁计数器
static KERNEL_MAPPER_LOCK_COUNT: AtomicUsize = AtomicUsize::new(0);
pub struct KernelMapper {
/// 内核空间映射器
mapper: PageMapper,
/// 标记当前映射器是否为只读
readonly: bool,
}
impl KernelMapper {
fn lock_cpu(cpuid: ProcessorId, mapper: PageMapper) -> Self {
loop {
match KERNEL_MAPPER_LOCK_OWNER.compare_exchange_weak(
KERNEL_MAPPER_NO_PROCESSOR,
cpuid,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => break,
// 当前处理器已经持有了锁
Err(id) if id == cpuid => break,
// either CAS failed, or some other hardware thread holds the lock
Err(_) => core::hint::spin_loop(),
}
}
let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_add(1, Ordering::Relaxed);
compiler_fence(Ordering::Acquire);
// 本地核心已经持有过锁,因此标记当前加锁获得的映射器为只读
let readonly = prev_count > 0;
return Self { mapper, readonly };
}
/// @brief 锁定内核映射器, 并返回一个内核映射器对象
#[inline(always)]
pub fn lock() -> Self {
let cpuid = smp_get_processor_id();
let mapper = unsafe { PageMapper::current(PageTableKind::Kernel, LockedFrameAllocator) };
return Self::lock_cpu(cpuid, mapper);
}
/// @brief 获取内核映射器的page mapper的可变引用。如果当前映射器为只读则返回 None
#[inline(always)]
pub fn as_mut(&mut self) -> Option<&mut PageMapper> {
if self.readonly {
return None;
} else {
return Some(&mut self.mapper);
}
}
/// @brief 获取内核映射器的page mapper的不可变引用
#[inline(always)]
pub fn as_ref(&self) -> &PageMapper {
return &self.mapper;
}
/// 映射一段物理地址到指定的虚拟地址。
///
/// ## 参数
///
/// - `vaddr`: 要映射的虚拟地址
/// - `paddr`: 要映射的物理地址
/// - `size`: 要映射的大小(字节,必须是页大小的整数倍,否则会向上取整)
/// - `flags`: 页面标志
/// - `flush`: 是否刷新TLB
///
/// ## 返回
///
/// - 成功返回Ok(())
/// - 失败: 如果当前映射器为只读则返回EAGAIN_OR_EWOULDBLOCK
pub unsafe fn map_phys_with_size(
&mut self,
mut vaddr: VirtAddr,
mut paddr: PhysAddr,
size: usize,
flags: PageFlags<MMArch>,
flush: bool,
) -> Result<(), SystemError> {
if self.readonly {
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
// kdebug!("kernel mapper: map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
for _ in 0..count.data() {
let flusher = self.mapper.map_phys(vaddr, paddr, flags).unwrap();
if flush {
flusher.flush();
}
vaddr += MMArch::PAGE_SIZE;
paddr += MMArch::PAGE_SIZE;
}
return Ok(());
}
}
impl Drop for KernelMapper {
fn drop(&mut self) {
// 为了防止fetch_sub和store之间由于中断导致store错误清除了owner导致错误因此需要关中断。
let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_sub(1, Ordering::Relaxed);
if prev_count == 1 {
KERNEL_MAPPER_LOCK_OWNER.store(KERNEL_MAPPER_NO_PROCESSOR, Ordering::Release);
}
drop(guard);
compiler_fence(Ordering::Release);
}
}
impl Deref for KernelMapper {
type Target = PageMapper;
fn deref(&self) -> &Self::Target {
return self.as_ref();
}
}