mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +00:00
feature: 增加early io remap的fixmap功能 (#495)
允许在内存管理初始化之前,使用fixmap功能,映射一些物理内存,并记录.
This commit is contained in:
parent
1f58c8f5cf
commit
74ffde667e
@ -23,7 +23,7 @@ backtrace = []
|
|||||||
|
|
||||||
# 运行时依赖项
|
# 运行时依赖项
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
|
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
|
||||||
atomic_enum = "0.2.0"
|
atomic_enum = "0.2.0"
|
||||||
bit_field = "0.10"
|
bit_field = "0.10"
|
||||||
bitfield-struct = "0.5.3"
|
bitfield-struct = "0.5.3"
|
||||||
@ -39,12 +39,12 @@ klog_types = { path = "crates/klog_types" }
|
|||||||
linkme = "0.2"
|
linkme = "0.2"
|
||||||
num = { version = "0.4.0", default-features = false }
|
num = { version = "0.4.0", default-features = false }
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
num-traits = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
|
num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
|
||||||
raw-cpuid = "11.0.1"
|
raw-cpuid = "11.0.1"
|
||||||
smoltcp = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
smoltcp = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
||||||
system_error = { path = "crates/system_error" }
|
system_error = { path = "crates/system_error" }
|
||||||
unified-init = { path = "crates/unified-init" }
|
unified-init = { path = "crates/unified-init" }
|
||||||
virtio-drivers = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
|
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
|
||||||
fdt = "0.1.5"
|
fdt = "0.1.5"
|
||||||
|
|
||||||
# target为x86_64时,使用下面的依赖
|
# target为x86_64时,使用下面的依赖
|
||||||
|
@ -11,7 +11,7 @@ pub(super) mod init;
|
|||||||
|
|
||||||
pub type PageMapper = crate::mm::page::PageMapper<RiscV64MMArch, LockedFrameAllocator>;
|
pub type PageMapper = crate::mm::page::PageMapper<RiscV64MMArch, LockedFrameAllocator>;
|
||||||
|
|
||||||
/// RiscV64的内存管理架构结构体
|
/// RiscV64的内存管理架构结构体(sv39)
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
pub struct RiscV64MMArch;
|
pub struct RiscV64MMArch;
|
||||||
|
|
||||||
@ -53,6 +53,11 @@ impl MemoryManagementArch for RiscV64MMArch {
|
|||||||
|
|
||||||
const USER_STACK_START: crate::mm::VirtAddr = VirtAddr::new(0x0000_001f_ffa0_0000);
|
const USER_STACK_START: crate::mm::VirtAddr = VirtAddr::new(0x0000_001f_ffa0_0000);
|
||||||
|
|
||||||
|
/// 在距离sv39的顶端还有1G的位置,设置为FIXMAP的起始地址
|
||||||
|
const FIXMAP_START_VADDR: VirtAddr = VirtAddr::new(0xffff_ffff_8000_0000);
|
||||||
|
/// 设置1MB的fixmap空间
|
||||||
|
const FIXMAP_SIZE: usize = 256 * 4096;
|
||||||
|
|
||||||
unsafe fn init() {
|
unsafe fn init() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,10 @@ impl MemoryManagementArch for X86_64MMArch {
|
|||||||
const USER_BRK_START: VirtAddr = VirtAddr::new(0x700000000000);
|
const USER_BRK_START: VirtAddr = VirtAddr::new(0x700000000000);
|
||||||
const USER_STACK_START: VirtAddr = VirtAddr::new(0x6ffff0a00000);
|
const USER_STACK_START: VirtAddr = VirtAddr::new(0x6ffff0a00000);
|
||||||
|
|
||||||
|
const FIXMAP_START_VADDR: VirtAddr = VirtAddr::new(0xffffb00000000000);
|
||||||
|
/// 设置FIXMAP区域大小为1M
|
||||||
|
const FIXMAP_SIZE: usize = 256 * 4096;
|
||||||
|
|
||||||
/// @brief 获取物理内存区域
|
/// @brief 获取物理内存区域
|
||||||
unsafe fn init() {
|
unsafe fn init() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
169
kernel/src/mm/early_ioremap.rs
Normal file
169
kernel/src/mm/early_ioremap.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::MMArch,
|
||||||
|
libs::{align::page_align_up, spinlock::SpinLock},
|
||||||
|
mm::no_init::{pseudo_map_phys, pseudo_unmap_phys},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{allocator::page_frame::PageFrameCount, MemoryManagementArch, PhysAddr, VirtAddr};
|
||||||
|
|
||||||
|
static SLOTS: SpinLock<[Slot; EarlyIoRemap::SLOT_CNT]> =
|
||||||
|
SpinLock::new([Slot::DEFAULT; EarlyIoRemap::SLOT_CNT]);
|
||||||
|
|
||||||
|
/// 早期IO映射机制
|
||||||
|
///
|
||||||
|
/// 该机制在内存管理初始化之前,提供IO重映射的功能。
|
||||||
|
///
|
||||||
|
/// ## 注意
|
||||||
|
///
|
||||||
|
/// 该机制使用固定大小的slot来记录所有的映射,
|
||||||
|
/// 而这些映射空间是有限的,由MMArch::FIXMAP_SIZE指定
|
||||||
|
pub struct EarlyIoRemap;
|
||||||
|
|
||||||
|
impl EarlyIoRemap {
|
||||||
|
const SLOT_CNT: usize = MMArch::FIXMAP_SIZE / MMArch::PAGE_SIZE;
|
||||||
|
|
||||||
|
/// 把物理内存映射到虚拟内存中
|
||||||
|
///
|
||||||
|
/// ## 说明
|
||||||
|
///
|
||||||
|
/// 虚拟内存由early io remap机制自动分配。
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - phys: 物理内存地址(需要按页对齐)
|
||||||
|
/// - size: 映射的内存大小
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// - 成功: (虚拟内存地址, 映射的内存大小)
|
||||||
|
/// - Err(SystemError::ENOMEM): 可用的slot不足
|
||||||
|
/// - Err(SystemError::EINVAL): 传入的物理地址没有对齐
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn map(phys: PhysAddr, size: usize) -> Result<(VirtAddr, usize), SystemError> {
|
||||||
|
if phys.check_aligned(MMArch::PAGE_SIZE) == false {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut slot_guard = SLOTS.lock();
|
||||||
|
|
||||||
|
let slot_count = PageFrameCount::from_bytes(page_align_up(size))
|
||||||
|
.unwrap()
|
||||||
|
.data();
|
||||||
|
// 寻找连续的slot
|
||||||
|
let mut start_slot = None;
|
||||||
|
for i in 0..(Self::SLOT_CNT - slot_count + 1) {
|
||||||
|
let mut is_continuous = true;
|
||||||
|
|
||||||
|
for j in 0..slot_count {
|
||||||
|
let slot_idx = i + j;
|
||||||
|
if slot_guard[slot_idx].start_idx.is_some() {
|
||||||
|
is_continuous = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_continuous {
|
||||||
|
start_slot = Some(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_slot = start_slot.ok_or(SystemError::ENOMEM)?;
|
||||||
|
let vaddr = Self::idx_to_virt(start_slot);
|
||||||
|
// 执行映射
|
||||||
|
unsafe { pseudo_map_phys(vaddr, phys, PageFrameCount::new(slot_count)) }
|
||||||
|
|
||||||
|
// 更新slot信息
|
||||||
|
let map_size = slot_count * MMArch::PAGE_SIZE;
|
||||||
|
for i in 0..slot_count {
|
||||||
|
let slot_idx = start_slot + i;
|
||||||
|
slot_guard[slot_idx].start_idx = Some(start_slot as u32);
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
slot_guard[slot_idx].size = map_size as u32;
|
||||||
|
slot_guard[slot_idx].phys = phys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok((vaddr, map_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 取消映射
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - virt: 映射范围内的任意虚拟地址
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// - Ok: 成功
|
||||||
|
/// - Err(SystemError::EINVAL): 传入的虚拟地址不在early io remap范围内,
|
||||||
|
/// 或者虚拟地址未映射
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn unmap(virt: VirtAddr) -> Result<(), SystemError> {
|
||||||
|
if virt < MMArch::FIXMAP_START_VADDR || virt >= MMArch::FIXMAP_END_VADDR {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut slot_guard = SLOTS.lock();
|
||||||
|
let mut idx = None;
|
||||||
|
|
||||||
|
// 寻找虚拟地址对应的区域的第一个slot
|
||||||
|
for slot_idx in 0..Self::SLOT_CNT {
|
||||||
|
let slot = &mut slot_guard[slot_idx];
|
||||||
|
if let Some(start_idx) = slot.start_idx {
|
||||||
|
if start_idx == slot_idx as u32 {
|
||||||
|
let vaddr_start = Self::idx_to_virt(start_idx as usize);
|
||||||
|
let vaddr_end = vaddr_start + slot.size as usize;
|
||||||
|
if vaddr_start <= virt && virt < vaddr_end {
|
||||||
|
// 找到区域了
|
||||||
|
idx = Some(slot_idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = idx.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
let vaddr = Self::idx_to_virt(idx as usize);
|
||||||
|
let count = PageFrameCount::from_bytes(slot_guard[idx].size as usize).unwrap();
|
||||||
|
|
||||||
|
// 取消映射
|
||||||
|
|
||||||
|
unsafe { pseudo_unmap_phys(vaddr, count) };
|
||||||
|
|
||||||
|
for i in 0..count.data() {
|
||||||
|
let slot_idx = idx + i;
|
||||||
|
let slot = &mut slot_guard[slot_idx];
|
||||||
|
*slot = Slot::DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把slot下标转换为这个slot对应的虚拟地址
|
||||||
|
fn idx_to_virt(idx: usize) -> VirtAddr {
|
||||||
|
MMArch::FIXMAP_START_VADDR + idx * MMArch::PAGE_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Slot {
|
||||||
|
/// 连续映射的起始槽位号
|
||||||
|
start_idx: Option<u32>,
|
||||||
|
/// 连续映射的区域大小(仅在起始槽位中设置)
|
||||||
|
size: u32,
|
||||||
|
/// 映射的起始物理地址
|
||||||
|
phys: PhysAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Slot {
|
||||||
|
const DEFAULT: Self = Self {
|
||||||
|
start_idx: None,
|
||||||
|
size: 0,
|
||||||
|
phys: PhysAddr::new(0),
|
||||||
|
};
|
||||||
|
}
|
@ -20,6 +20,7 @@ use self::{
|
|||||||
|
|
||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod c_adapter;
|
pub mod c_adapter;
|
||||||
|
pub mod early_ioremap;
|
||||||
pub mod kernel_mapper;
|
pub mod kernel_mapper;
|
||||||
pub mod memblock;
|
pub mod memblock;
|
||||||
pub mod mmio_buddy;
|
pub mod mmio_buddy;
|
||||||
@ -92,7 +93,7 @@ impl PhysAddr {
|
|||||||
|
|
||||||
/// @brief 获取物理地址的值
|
/// @brief 获取物理地址的值
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn data(&self) -> usize {
|
pub const fn data(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ impl VirtAddr {
|
|||||||
|
|
||||||
/// @brief 获取虚拟地址的值
|
/// @brief 获取虚拟地址的值
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn data(&self) -> usize {
|
pub const fn data(&self) -> usize {
|
||||||
return self.0;
|
return self.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,6 +430,14 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
|
|||||||
/// 用户栈起始地址(向下生长,不包含该值)
|
/// 用户栈起始地址(向下生长,不包含该值)
|
||||||
const USER_STACK_START: VirtAddr;
|
const USER_STACK_START: VirtAddr;
|
||||||
|
|
||||||
|
/// 内核的固定映射区的起始地址
|
||||||
|
const FIXMAP_START_VADDR: VirtAddr;
|
||||||
|
/// 内核的固定映射区的大小
|
||||||
|
const FIXMAP_SIZE: usize;
|
||||||
|
/// 内核的固定映射区的结束地址
|
||||||
|
const FIXMAP_END_VADDR: VirtAddr =
|
||||||
|
VirtAddr::new(Self::FIXMAP_START_VADDR.data() + Self::FIXMAP_SIZE);
|
||||||
|
|
||||||
/// @brief 用于初始化内存管理模块与架构相关的信息。
|
/// @brief 用于初始化内存管理模块与架构相关的信息。
|
||||||
/// 该函数应调用其他模块的接口,把可用内存区域添加到memblock,提供给BumpAllocator使用
|
/// 该函数应调用其他模块的接口,把可用内存区域添加到memblock,提供给BumpAllocator使用
|
||||||
unsafe fn init();
|
unsafe fn init();
|
||||||
|
@ -137,6 +137,7 @@ impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
|
|||||||
/// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为
|
/// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为
|
||||||
///
|
///
|
||||||
/// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准)
|
/// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准)
|
||||||
|
#[inline(never)]
|
||||||
pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
|
pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
|
||||||
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
|
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
|
||||||
assert!(paddr.check_aligned(MMArch::PAGE_SIZE));
|
assert!(paddr.check_aligned(MMArch::PAGE_SIZE));
|
||||||
@ -160,3 +161,31 @@ pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrame
|
|||||||
|
|
||||||
mapper.make_current();
|
mapper.make_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unmap physical memory from virtual memory.
|
||||||
|
///
|
||||||
|
/// ## 说明
|
||||||
|
///
|
||||||
|
/// 该函数在系统启动早期,内存管理尚未初始化的时候使用
|
||||||
|
#[inline(never)]
|
||||||
|
pub unsafe fn pseudo_unmap_phys(vaddr: VirtAddr, count: PageFrameCount) {
|
||||||
|
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
|
||||||
|
assert!(count.data() == 1);
|
||||||
|
|
||||||
|
let mut pseudo_allocator = PseudoAllocator::<MMArch>::new();
|
||||||
|
|
||||||
|
let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new(
|
||||||
|
PageTableKind::Kernel,
|
||||||
|
MMArch::table(PageTableKind::Kernel),
|
||||||
|
&mut pseudo_allocator,
|
||||||
|
);
|
||||||
|
|
||||||
|
for i in 0..count.data() {
|
||||||
|
let vaddr = vaddr + i * MMArch::PAGE_SIZE;
|
||||||
|
mapper.unmap_phys(vaddr, true).map(|(_, _, flusher)| {
|
||||||
|
flusher.ignore();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper.make_current();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user