diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0aac6633..02af0d2d 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,7 +23,7 @@ backtrace = [] # 运行时依赖项 [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" bit_field = "0.10" bitfield-struct = "0.5.3" @@ -39,12 +39,12 @@ klog_types = { path = "crates/klog_types" } linkme = "0.2" num = { version = "0.4.0", default-features = false } 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" -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" } 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" # target为x86_64时,使用下面的依赖 diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index d949e078..aec63b7a 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -11,7 +11,7 @@ pub(super) mod init; pub type PageMapper = crate::mm::page::PageMapper; -/// RiscV64的内存管理架构结构体 +/// RiscV64的内存管理架构结构体(sv39) #[derive(Debug, Clone, Copy, Hash)] pub struct RiscV64MMArch; @@ -53,6 +53,11 @@ impl MemoryManagementArch for RiscV64MMArch { 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() { todo!() } diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 1f8fc926..ab50834a 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -115,6 +115,10 @@ impl MemoryManagementArch for X86_64MMArch { const USER_BRK_START: VirtAddr = VirtAddr::new(0x700000000000); 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 获取物理内存区域 unsafe fn init() { extern "C" { diff --git a/kernel/src/mm/early_ioremap.rs b/kernel/src/mm/early_ioremap.rs new file mode 100644 index 00000000..5acbc444 --- /dev/null +++ b/kernel/src/mm/early_ioremap.rs @@ -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, + /// 连续映射的区域大小(仅在起始槽位中设置) + size: u32, + /// 映射的起始物理地址 + phys: PhysAddr, +} + +impl Slot { + const DEFAULT: Self = Self { + start_idx: None, + size: 0, + phys: PhysAddr::new(0), + }; +} diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 97aaa363..531f88f9 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -20,6 +20,7 @@ use self::{ pub mod allocator; pub mod c_adapter; +pub mod early_ioremap; pub mod kernel_mapper; pub mod memblock; pub mod mmio_buddy; @@ -92,7 +93,7 @@ impl PhysAddr { /// @brief 获取物理地址的值 #[inline(always)] - pub fn data(&self) -> usize { + pub const fn data(&self) -> usize { self.0 } @@ -211,7 +212,7 @@ impl VirtAddr { /// @brief 获取虚拟地址的值 #[inline(always)] - pub fn data(&self) -> usize { + pub const fn data(&self) -> usize { return self.0; } @@ -429,6 +430,14 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { /// 用户栈起始地址(向下生长,不包含该值) 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 用于初始化内存管理模块与架构相关的信息。 /// 该函数应调用其他模块的接口,把可用内存区域添加到memblock,提供给BumpAllocator使用 unsafe fn init(); diff --git a/kernel/src/mm/no_init.rs b/kernel/src/mm/no_init.rs index 4c198e93..111346d1 100644 --- a/kernel/src/mm/no_init.rs +++ b/kernel/src/mm/no_init.rs @@ -137,6 +137,7 @@ impl FrameAllocator for PseudoAllocator { /// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为 /// /// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准) +#[inline(never)] pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) { assert!(vaddr.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(); } + +/// 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::::new(); + + let mut mapper = crate::mm::page::PageMapper::::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(); +}