From 45626c859f95054b76d8b59afcbd24c6b235026f Mon Sep 17 00:00:00 2001 From: LoGin Date: Wed, 3 Jan 2024 18:00:47 +0800 Subject: [PATCH] =?UTF-8?q?riscv:=20=E8=A7=A3=E6=9E=90dtb=EF=BC=8C?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=8F=AF=E7=94=A8=E5=86=85=E5=AD=98=E7=A9=BA?= =?UTF-8?q?=E9=97=B4=E5=B9=B6=E6=B7=BB=E5=8A=A0=E5=88=B0memblock=20(#486)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/Cargo.toml | 6 + kernel/src/arch/riscv64/init/mod.rs | 57 +++- kernel/src/arch/riscv64/mm/mod.rs | 2 +- kernel/src/arch/riscv64/mod.rs | 2 +- kernel/src/arch/x86_64/init/mod.rs | 6 + kernel/src/arch/x86_64/mm/bump.rs | 9 +- kernel/src/arch/x86_64/mm/mod.rs | 45 ++-- kernel/src/arch/x86_64/mod.rs | 1 + kernel/src/driver/mod.rs | 1 + kernel/src/driver/open_firmware/fdt.rs | 300 +++++++++++++++++++++ kernel/src/driver/open_firmware/mod.rs | 2 + kernel/src/init/mod.rs | 56 ++++ kernel/src/mm/allocator/bump.rs | 32 +-- kernel/src/mm/memblock.rs | 351 +++++++++++++++++++++++++ kernel/src/mm/mod.rs | 15 +- kernel/submodules/DragonStub | 2 +- 16 files changed, 837 insertions(+), 50 deletions(-) create mode 100644 kernel/src/arch/x86_64/init/mod.rs create mode 100644 kernel/src/driver/open_firmware/fdt.rs create mode 100644 kernel/src/driver/open_firmware/mod.rs create mode 100644 kernel/src/mm/memblock.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index e261c04f..23f5b7bf 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,6 +44,7 @@ smoltcp = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/smoltcp.g 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" } +fdt = "0.1.5" # target为x86_64时,使用下面的依赖 [target.'cfg(target_arch = "x86_64")'.dependencies] @@ -52,6 +53,11 @@ x86 = "0.52.0" x86_64 = "0.14.10" +# target为riscv64时,使用下面的依赖 +[target.'cfg(target_arch = "riscv64")'.dependencies] + + + # 构建时依赖项 [build-dependencies] kernel_build = { path = "../build-scripts/kernel_build" } diff --git a/kernel/src/arch/riscv64/init/mod.rs b/kernel/src/arch/riscv64/init/mod.rs index 43b3a079..5117e725 100644 --- a/kernel/src/arch/riscv64/init/mod.rs +++ b/kernel/src/arch/riscv64/init/mod.rs @@ -1,16 +1,71 @@ use core::intrinsics::unreachable; -use crate::{init::init_before_mem_init, kinfo, mm::PhysAddr}; +use fdt::node::FdtNode; + +use crate::{ + driver::open_firmware::fdt::open_firmware_fdt_driver, + init::{boot_params, init_before_mem_init}, + kinfo, + mm::{PhysAddr, VirtAddr}, + print, println, +}; + +#[derive(Debug)] +pub struct ArchBootParams { + /// 启动时的fdt物理地址 + pub fdt_paddr: PhysAddr, +} + +impl ArchBootParams { + pub const DEFAULT: Self = ArchBootParams { + fdt_paddr: PhysAddr::new(0), + }; +} #[no_mangle] unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! { let fdt_paddr = PhysAddr::new(fdt_paddr); init_before_mem_init(); + boot_params().write().arch.fdt_paddr = fdt_paddr; kinfo!( "DragonOS kernel is running on hart {}, fdt address:{:?}", hartid, fdt_paddr ); + + let fdt = fdt::Fdt::from_ptr(fdt_paddr.data() as *const u8).expect("Failed to parse fdt!"); + print_node(fdt.find_node("/").unwrap(), 0); + + parse_dtb(); + loop {} unreachable() } + +fn print_node(node: FdtNode<'_, '_>, n_spaces: usize) { + (0..n_spaces).for_each(|_| print!(" ")); + println!("{}/", node.name); + node.properties().for_each(|p| { + (0..n_spaces + 4).for_each(|_| print!(" ")); + println!("{}: {:?}", p.name, p.value); + }); + + for child in node.children() { + print_node(child, n_spaces + 4); + } +} + +/// 解析fdt,获取内核启动参数 +unsafe fn parse_dtb() { + let fdt_paddr = boot_params().read().arch.fdt_paddr; + if fdt_paddr.is_null() { + panic!("Failed to get fdt address!"); + } + + open_firmware_fdt_driver() + .set_fdt_vaddr(VirtAddr::new(fdt_paddr.data())) + .unwrap(); + open_firmware_fdt_driver() + .early_scan_device_tree() + .expect("Failed to scan device tree at boottime."); +} diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index d9afb73b..d949e078 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -53,7 +53,7 @@ impl MemoryManagementArch for RiscV64MMArch { const USER_STACK_START: crate::mm::VirtAddr = VirtAddr::new(0x0000_001f_ffa0_0000); - unsafe fn init() -> &'static [crate::mm::PhysMemoryArea] { + unsafe fn init() { todo!() } diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs index 22c14cec..e6dcf0c8 100644 --- a/kernel/src/arch/riscv64/mod.rs +++ b/kernel/src/arch/riscv64/mod.rs @@ -1,7 +1,7 @@ pub mod asm; pub mod cpu; pub mod driver; -mod init; +pub mod init; pub mod interrupt; pub mod ipc; mod kvm; diff --git a/kernel/src/arch/x86_64/init/mod.rs b/kernel/src/arch/x86_64/init/mod.rs new file mode 100644 index 00000000..d3bed100 --- /dev/null +++ b/kernel/src/arch/x86_64/init/mod.rs @@ -0,0 +1,6 @@ +#[derive(Debug)] +pub struct ArchBootParams {} + +impl ArchBootParams { + pub const DEFAULT: Self = ArchBootParams {}; +} diff --git a/kernel/src/arch/x86_64/mm/bump.rs b/kernel/src/arch/x86_64/mm/bump.rs index dd5968ca..d5273dc6 100644 --- a/kernel/src/arch/x86_64/mm/bump.rs +++ b/kernel/src/arch/x86_64/mm/bump.rs @@ -1,12 +1,12 @@ use crate::{ - kdebug, libs::align::{page_align_down, page_align_up}, mm::{ - allocator::bump::BumpAllocator, MemoryManagementArch, PhysAddr, PhysMemoryArea, VirtAddr, + allocator::bump::BumpAllocator, memblock::mem_block_manager, MemoryManagementArch, + PhysAddr, PhysMemoryArea, VirtAddr, }, }; -use super::{X86_64MMBootstrapInfo, BOOTSTRAP_MM_INFO, PHYS_MEMORY_AREAS}; +use super::{X86_64MMBootstrapInfo, BOOTSTRAP_MM_INFO}; impl BumpAllocator { pub unsafe fn arch_remain_areas( @@ -23,7 +23,7 @@ impl BumpAllocator { let offset_end = page_align_down(kernel_code_start - 16384); // 把内核代码前的空间加入到可用内存区域中 - for area in &PHYS_MEMORY_AREAS { + for area in mem_block_manager().to_iter() { let area_base = area.area_base_aligned().data(); let area_end = area.area_end_aligned().data(); if area_base >= offset_end { @@ -44,7 +44,6 @@ impl BumpAllocator { ret_areas[res_count] = PhysMemoryArea::new(PhysAddr::new(new_start), new_end - new_start); - kdebug!("new arch remain area: {:?}", ret_areas[res_count]); res_count += 1; } diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 92d0ed37..1f8fc926 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -18,6 +18,7 @@ use crate::libs::printk::PrintkWriter; use crate::libs::spinlock::SpinLock; use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}; +use crate::mm::memblock::mem_block_manager; use crate::mm::mmio_buddy::mmio_init; use crate::{ arch::MMArch, @@ -26,8 +27,8 @@ use crate::{ use crate::mm::kernel_mapper::KernelMapper; use crate::mm::page::{PageEntry, PageFlags}; -use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, PhysMemoryArea, VirtAddr}; -use crate::{kdebug, kinfo}; +use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr}; +use crate::{kdebug, kinfo, kwarn}; use system_error::SystemError; use core::arch::asm; @@ -43,12 +44,6 @@ use super::kvm::vmx::vmx_asm_wrapper::vmx_vmread; pub type PageMapper = crate::mm::page::PageMapper; -/// @brief 用于存储物理内存区域的数组 -static mut PHYS_MEMORY_AREAS: [PhysMemoryArea; 512] = [PhysMemoryArea { - base: PhysAddr::new(0), - size: 0, -}; 512]; - /// 初始的CR3寄存器的值,用于内存管理初始化时,创建的第一个内核页表的位置 static mut INITIAL_CR3_VALUE: PhysAddr = PhysAddr::new(0); @@ -121,7 +116,7 @@ impl MemoryManagementArch for X86_64MMArch { const USER_STACK_START: VirtAddr = VirtAddr::new(0x6ffff0a00000); /// @brief 获取物理内存区域 - unsafe fn init() -> &'static [crate::mm::PhysMemoryArea] { + unsafe fn init() { extern "C" { fn _text(); fn _etext(); @@ -147,12 +142,9 @@ impl MemoryManagementArch for X86_64MMArch { } // 初始化物理内存区域(从multiboot2中获取) - let areas_count = - Self::init_memory_area_from_multiboot2().expect("init memory area failed"); + Self::init_memory_area_from_multiboot2().expect("init memory area failed"); send_to_default_serial8250_port("x86 64 init end\n\0".as_bytes()); - - return &PHYS_MEMORY_AREAS[0..areas_count]; } /// @brief 刷新TLB中,关于指定虚拟地址的条目 @@ -336,9 +328,24 @@ impl X86_64MMArch { if mb2_mem_info[i].len == 0 { continue; } + total_mem_size += mb2_mem_info[i].len as usize; - PHYS_MEMORY_AREAS[areas_count].base = PhysAddr::new(mb2_mem_info[i].addr as usize); - PHYS_MEMORY_AREAS[areas_count].size = mb2_mem_info[i].len as usize; + // PHYS_MEMORY_AREAS[areas_count].base = PhysAddr::new(mb2_mem_info[i].addr as usize); + // PHYS_MEMORY_AREAS[areas_count].size = mb2_mem_info[i].len as usize; + + mem_block_manager() + .add_block( + PhysAddr::new(mb2_mem_info[i].addr as usize), + mb2_mem_info[i].len as usize, + ) + .unwrap_or_else(|e| { + kwarn!( + "Failed to add memory block: base={:#x}, size={:#x}, error={:?}", + mb2_mem_info[i].addr, + mb2_mem_info[i].len, + e + ); + }); areas_count += 1; } } @@ -412,9 +419,7 @@ unsafe fn allocator_init() { let phy_offset = unsafe { MMArch::virt_2_phys(VirtAddr::new(page_align_up(virt_offset))) }.unwrap(); - kdebug!("PhysArea[0..10] = {:?}", &PHYS_MEMORY_AREAS[0..10]); - let mut bump_allocator = - BumpAllocator::::new(&PHYS_MEMORY_AREAS, phy_offset.data()); + let mut bump_allocator = BumpAllocator::::new(phy_offset.data()); kdebug!( "BumpAllocator created, offset={:?}", bump_allocator.offset() @@ -450,7 +455,9 @@ unsafe fn allocator_init() { } kdebug!("Successfully emptied page table"); - for area in PHYS_MEMORY_AREAS.iter() { + let total_num = mem_block_manager().total_initial_memory_regions(); + for i in 0..total_num { + let area = mem_block_manager().get_initial_memory_region(i).unwrap(); // kdebug!("area: base={:?}, size={:#x}, end={:?}", area.base, area.size, area.base + area.size); for i in 0..((area.size + MMArch::PAGE_SIZE - 1) / MMArch::PAGE_SIZE) { let paddr = area.base.add(i * MMArch::PAGE_SIZE); diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 6e298669..6835efbc 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -5,6 +5,7 @@ mod c_adapter; pub mod cpu; pub mod driver; pub mod fpu; +pub mod init; pub mod interrupt; pub mod ipc; pub mod kvm; diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index ee5767ac..e506ca0e 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -3,6 +3,7 @@ pub mod base; pub mod disk; pub mod keyboard; pub mod net; +pub mod open_firmware; pub mod pci; pub mod timers; pub mod tty; diff --git a/kernel/src/driver/open_firmware/fdt.rs b/kernel/src/driver/open_firmware/fdt.rs new file mode 100644 index 00000000..7ec6027f --- /dev/null +++ b/kernel/src/driver/open_firmware/fdt.rs @@ -0,0 +1,300 @@ +use fdt::{ + node::{FdtNode, NodeProperty}, + Fdt, +}; +use system_error::SystemError; + +use crate::{ + arch::MMArch, + init::boot_params, + libs::{align::page_align_down, rwlock::RwLock}, + mm::{ + memblock::{mem_block_manager, MemBlockManager}, + MemoryManagementArch, PhysAddr, VirtAddr, + }, +}; + +#[inline(always)] +pub fn open_firmware_fdt_driver() -> &'static OpenFirmwareFdtDriver { + &OpenFirmwareFdtDriver +} + +static FDT_GLOBAL_DATA: RwLock = RwLock::new(FdtGlobalData::new()); + +#[derive(Debug)] +struct FdtGlobalData { + /// FDT根节点下的`size-cells`属性值 + root_size_cells: u32, + + /// FDT根节点下的`address-cells`属性值 + root_addr_cells: u32, + + chosen_node_name: Option<&'static str>, +} + +impl FdtGlobalData { + pub const fn new() -> Self { + Self { + root_size_cells: 1, + root_addr_cells: 1, + chosen_node_name: None, + } + } +} + +static mut FDT_VADDR: Option = None; + +pub struct OpenFirmwareFdtDriver; + +impl OpenFirmwareFdtDriver { + pub fn early_scan_device_tree(&self) -> Result<(), SystemError> { + let fdt_vaddr = unsafe { FDT_VADDR.ok_or(SystemError::EINVAL)? }; + let fdt = unsafe { + fdt::Fdt::from_ptr(fdt_vaddr.as_ptr()).map_err(|e| { + kerror!("failed to parse fdt, err={:?}", e); + SystemError::EINVAL + }) + }?; + + self.early_init_scan_nodes(&fdt); + + return Ok(()); + } + + fn early_init_scan_nodes(&self, fdt: &Fdt) { + self.early_init_scan_root(fdt) + .expect("Failed to scan fdt root node."); + + self.early_init_scan_chosen(fdt).unwrap_or_else(|_| { + kwarn!("No `chosen` node found"); + }); + + self.early_init_scan_memory(fdt); + } + + /// 扫描根节点 + fn early_init_scan_root(&self, fdt: &Fdt) -> Result<(), SystemError> { + let node = fdt.find_node("/").ok_or(SystemError::ENODEV)?; + + let mut guard = FDT_GLOBAL_DATA.write(); + + if let Some(prop) = node.property("#size-cells") { + guard.root_size_cells = prop.as_usize().unwrap() as u32; + + kdebug!("fdt_root_size_cells={}", guard.root_size_cells); + } + + if let Some(prop) = node.property("#address-cells") { + guard.root_addr_cells = prop.as_usize().unwrap() as u32; + + kdebug!("fdt_root_addr_cells={}", guard.root_addr_cells); + } + + return Ok(()); + } + + /// 扫描 `/chosen` 节点 + fn early_init_scan_chosen(&self, fdt: &Fdt) -> Result<(), SystemError> { + const CHOSEN_NAME1: &'static str = "/chosen"; + let mut node = fdt.find_node(CHOSEN_NAME1); + if node.is_none() { + const CHOSEN_NAME2: &'static str = "/chosen@0"; + node = fdt.find_node(CHOSEN_NAME2); + if node.is_some() { + FDT_GLOBAL_DATA.write().chosen_node_name = Some(CHOSEN_NAME2); + } + } else { + FDT_GLOBAL_DATA.write().chosen_node_name = Some(CHOSEN_NAME1); + } + + if let Some(node) = node { + if let Some(prop) = node.property("bootargs") { + let bootargs = prop.as_str().unwrap(); + + boot_params() + .write() + .boot_cmdline_append(bootargs.as_bytes()); + } + } + + // TODO: 拼接内核自定义的command line参数 + + kdebug!("Command line: {}", boot_params().read().boot_cmdline_str()); + return Ok(()); + } + + /// 扫描 `/memory` 节点 + /// + /// ## 参数 + /// + /// - `fdt`:FDT + /// + /// ## 返回值 + /// + /// 如果扫描成功,找到可用内存,则返回`true`,否则返回`false`。 + fn early_init_scan_memory(&self, fdt: &Fdt) -> bool { + let mut found_memory = false; + for node in fdt.all_nodes() { + let device_type: Option> = node.property("device_type"); + if device_type.is_none() { + continue; + } + let device_type = device_type.unwrap().as_str(); + if device_type.is_none() || device_type.unwrap() != "memory" { + continue; + } + + if !self.is_device_avaliable(&node) { + continue; + } + + let reg = node.property("reg"); + if reg.is_none() { + continue; + } + let reg = reg.unwrap(); + // 每个cell是4字节 + let addr_cells = FDT_GLOBAL_DATA.read().root_addr_cells as usize; + let size_cells = FDT_GLOBAL_DATA.read().root_size_cells as usize; + + let total_elements_in_reg = reg.value.len() / ((addr_cells + size_cells) * 4); + + for i in 0..total_elements_in_reg { + let mut base_index = i * (addr_cells + size_cells); + let base: u64; + let size: u64; + match addr_cells { + 1 => { + base = u32::from_be_bytes( + reg.value[base_index..base_index + 4].try_into().unwrap(), + ) as u64; + } + 2 => { + base = u64::from_be_bytes( + reg.value[base_index..base_index + 8].try_into().unwrap(), + ); + } + _ => { + panic!("addr_cells must be 1 or 2"); + } + } + base_index += addr_cells * 4; + + match size_cells { + 1 => { + size = u32::from_be_bytes( + reg.value[base_index..base_index + 4].try_into().unwrap(), + ) as u64; + } + 2 => { + size = u64::from_be_bytes( + reg.value[base_index..base_index + 8].try_into().unwrap(), + ); + } + _ => { + panic!("size_cells must be 1 or 2"); + } + } + + if size == 0 { + continue; + } + + kdebug!("Found memory: base={:#x}, size={:#x}", base, size); + self.early_init_dt_add_memory(base, size); + found_memory = true; + } + } + + return found_memory; + } + + fn early_init_dt_add_memory(&self, base: u64, size: u64) { + let mut base = base as usize; + let mut size = size as usize; + + if size < (MMArch::PAGE_SIZE - (base & (!MMArch::PAGE_MASK))) { + kwarn!("Ignoring memory block {:#x}-{:#x}", base, base + size); + } + + if PhysAddr::new(base).check_aligned(MMArch::PAGE_SIZE) == false { + size -= MMArch::PAGE_SIZE - (base & (!MMArch::PAGE_MASK)); + base = page_align_down(base); + } + + size = page_align_down(size); + + if base > MemBlockManager::MAX_MEMBLOCK_ADDR.data() { + kwarn!("Ignoring memory block {:#x}-{:#x}", base, base + size); + } + + if base + size - 1 > MemBlockManager::MAX_MEMBLOCK_ADDR.data() { + kwarn!( + "Ignoring memory range {:#x}-{:#x}", + MemBlockManager::MAX_MEMBLOCK_ADDR.data() + 1, + base + size + ); + size = MemBlockManager::MAX_MEMBLOCK_ADDR.data() - base + 1; + } + + if base + size < MemBlockManager::MIN_MEMBLOCK_ADDR.data() { + kwarn!("Ignoring memory range {:#x}-{:#x}", base, base + size); + return; + } + + if base < MemBlockManager::MIN_MEMBLOCK_ADDR.data() { + { + kwarn!( + "Ignoring memory range {:#x}-{:#x}", + base, + MemBlockManager::MIN_MEMBLOCK_ADDR.data() + ); + size -= MemBlockManager::MIN_MEMBLOCK_ADDR.data() - base; + base = MemBlockManager::MIN_MEMBLOCK_ADDR.data(); + } + + mem_block_manager() + .add_block(PhysAddr::new(base), size) + .unwrap_or_else(|e| { + panic!( + "Failed to add memory block '{:#x}-{:#x}', err={:?}", + base, + base + size, + e + ); + }); + } + } + + fn is_device_avaliable(&self, node: &FdtNode) -> bool { + let status = node.property("status"); + if status.is_none() { + return true; + } + + let status = status.unwrap().as_str(); + if let Some(status) = status { + if status == "okay" || status == "ok" { + return true; + } + } + + return false; + } + + pub unsafe fn set_fdt_vaddr(&self, vaddr: VirtAddr) -> Result<(), SystemError> { + if vaddr.is_null() { + return Err(SystemError::EINVAL); + } + fdt::Fdt::from_ptr(vaddr.as_ptr()).map_err(|e| { + kerror!("failed to parse fdt, err={:?}", e); + SystemError::EINVAL + })?; + + unsafe { + FDT_VADDR = Some(vaddr); + } + + Ok(()) + } +} diff --git a/kernel/src/driver/open_firmware/mod.rs b/kernel/src/driver/open_firmware/mod.rs new file mode 100644 index 00000000..4c30d74a --- /dev/null +++ b/kernel/src/driver/open_firmware/mod.rs @@ -0,0 +1,2 @@ +#[cfg(target_arch = "riscv64")] +pub mod fdt; diff --git a/kernel/src/init/mod.rs b/kernel/src/init/mod.rs index c92a4f6f..a2a65bfa 100644 --- a/kernel/src/init/mod.rs +++ b/kernel/src/init/mod.rs @@ -1,4 +1,7 @@ +use core::cmp::min; + use crate::{ + arch::init::ArchBootParams, driver::{ tty::init::tty_early_init, video::{fbdev::base::BootTimeScreenInfo, VideoRefreshManager}, @@ -33,14 +36,67 @@ pub fn init_before_mem_init() { #[derive(Debug)] pub struct BootParams { pub screen_info: BootTimeScreenInfo, + pub arch: ArchBootParams, + boot_command_line: [u8; Self::BOOT_COMMAND_LINE_SIZE], } impl BootParams { const DEFAULT: Self = BootParams { screen_info: BootTimeScreenInfo::DEFAULT, + arch: ArchBootParams::DEFAULT, + boot_command_line: [0u8; Self::BOOT_COMMAND_LINE_SIZE], }; + /// 开机命令行参数字符串最大大小 + pub const BOOT_COMMAND_LINE_SIZE: usize = 2048; + const fn new() -> Self { Self::DEFAULT } + + /// 开机命令行参数(原始字节数组) + #[allow(dead_code)] + pub fn boot_cmdline(&self) -> &[u8] { + &self.boot_command_line + } + + /// 开机命令行参数字符串 + pub fn boot_cmdline_str(&self) -> &str { + core::str::from_utf8(self.boot_cmdline()).unwrap() + } + + /// 追加开机命令行参数 + /// + /// 如果开机命令行参数已经满了,则不会追加。 + /// 如果超过了最大长度,则截断。 + /// + /// ## 参数 + /// + /// - `data`:追加的数据 + pub fn boot_cmdline_append(&mut self, data: &[u8]) { + if data.is_empty() { + return; + } + + let mut pos: Option = None; + // 寻找结尾 + for (i, x) in self.boot_command_line.iter().enumerate() { + if *x == 0 { + pos = Some(i); + break; + } + } + let pos = pos.unwrap_or_else(|| self.boot_command_line.len() - 1) as isize; + + let avail = self.boot_command_line.len() as isize - pos - 1; + if avail <= 0 { + return; + } + + let len = min(avail as usize, data.len()); + let pos = pos as usize; + self.boot_command_line[pos..pos + len].copy_from_slice(&data[0..len]); + + self.boot_command_line[pos + len] = 0; + } } diff --git a/kernel/src/mm/allocator/bump.rs b/kernel/src/mm/allocator/bump.rs index ec11dbb5..8b2fbc20 100644 --- a/kernel/src/mm/allocator/bump.rs +++ b/kernel/src/mm/allocator/bump.rs @@ -3,13 +3,11 @@ /// @FilePath: /DragonOS/kernel/src/mm/allocator/bump.rs /// @Description: bump allocator线性分配器 use super::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}; -use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea}; +use crate::mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr, PhysMemoryArea}; use core::marker::PhantomData; /// 线性分配器 pub struct BumpAllocator { - // 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。 - areas: &'static [PhysMemoryArea], // 表示当前分配的物理内存的偏移量. offset: usize, // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。 @@ -22,17 +20,13 @@ impl BumpAllocator { /// @param Fareas 当前的内存区域 /// @param offset 当前的偏移量 /// @return 分配器本身 - pub fn new(areas: &'static [PhysMemoryArea], offset: usize) -> Self { + pub fn new(offset: usize) -> Self { Self { - areas, offset, phantom: PhantomData, } } - // @brief 获取页帧使用情况 - pub fn areas(&self) -> &'static [PhysMemoryArea] { - return self.areas; - } + // @brief 获取当前分配的物理内存的偏移量 pub fn offset(&self) -> usize { return self.offset; @@ -51,9 +45,10 @@ impl BumpAllocator { let mut res_cnt = 0; + let total_num = mem_block_manager().total_initial_memory_regions(); // 遍历所有的物理内存区域 - for i in 0..self.areas().len() { - let area = &self.areas()[i]; + for i in 0..total_num { + let area = mem_block_manager().get_initial_memory_region(i).unwrap(); // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整 // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT); let area_base = area.area_base_aligned().data(); @@ -75,9 +70,10 @@ impl BumpAllocator { } // found if offset + 1 * MMA::PAGE_SIZE <= area_end { - for j in i..self.areas().len() { - if self.areas()[j].area_base_aligned() < self.areas()[j].area_end_aligned() { - result_area[res_cnt] = self.areas()[j]; + for j in i..total_num { + let aj = mem_block_manager().get_initial_memory_region(j).unwrap(); + if aj.area_base_aligned() < aj.area_end_aligned() { + result_area[res_cnt] = aj; res_cnt += 1; } } @@ -102,8 +98,11 @@ impl FrameAllocator for BumpAllocator { /// @return 分配后的物理地址 unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> { let mut offset = self.offset(); + + let iter = mem_block_manager().to_iter(); + // 遍历所有的物理内存区域 - for area in self.areas().iter() { + for area in iter { // 将area的base地址与PAGE_SIZE对齐,对齐时向上取整 // let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT); let area_base = area.area_base_aligned().data(); @@ -145,7 +144,8 @@ impl FrameAllocator for BumpAllocator { unsafe fn usage(&self) -> PageFrameUsage { let mut total = 0; let mut used = 0; - for area in self.areas().iter() { + let iter = mem_block_manager().to_iter(); + for area in iter { // 将area的base地址与PAGE_SIZE对齐,对其时向上取整 let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT); // 将area的末尾地址与PAGE_SIZE对齐,对其时向下取整 diff --git a/kernel/src/mm/memblock.rs b/kernel/src/mm/memblock.rs new file mode 100644 index 00000000..76c47f59 --- /dev/null +++ b/kernel/src/mm/memblock.rs @@ -0,0 +1,351 @@ +use system_error::SystemError; + +use crate::libs::spinlock::{SpinLock, SpinLockGuard}; + +use super::{PhysAddr, PhysMemoryArea}; + +pub const INITIAL_MEMORY_REGIONS_NUM: usize = 128; + +/// 初始内存区域 +static MEM_BLOCK_MANAGER: MemBlockManager = MemBlockManager::new(); + +#[inline(always)] +pub fn mem_block_manager() -> &'static MemBlockManager { + &MEM_BLOCK_MANAGER +} + +/// 内存区域管理器 +#[derive(Debug)] +pub struct MemBlockManager { + inner: SpinLock, +} + +#[derive(Debug)] +pub struct InnerMemBlockManager { + /// 初始内存区域 + /// + /// 用于记录内核启动时的内存布局, 这些区域保持升序、不重叠 + initial_memory_regions: [PhysMemoryArea; INITIAL_MEMORY_REGIONS_NUM], + initial_memory_regions_num: usize, +} + +impl MemBlockManager { + #[allow(dead_code)] + pub const MIN_MEMBLOCK_ADDR: PhysAddr = PhysAddr::new(0); + #[allow(dead_code)] + pub const MAX_MEMBLOCK_ADDR: PhysAddr = PhysAddr::new(usize::MAX); + const fn new() -> Self { + Self { + inner: SpinLock::new(InnerMemBlockManager { + initial_memory_regions: [PhysMemoryArea::DEFAULT; INITIAL_MEMORY_REGIONS_NUM], + initial_memory_regions_num: 0, + }), + } + } + + /// 添加内存区域 + /// + /// 如果添加的区域与已有区域有重叠,会将重叠的区域合并 + #[allow(dead_code)] + pub fn add_block(&self, base: PhysAddr, size: usize) -> Result<(), SystemError> { + if size == 0 { + return Ok(()); + } + let mut inner = self.inner.lock(); + if inner.initial_memory_regions_num >= INITIAL_MEMORY_REGIONS_NUM { + panic!("Too many memory regions!"); + } + + let block = PhysMemoryArea::new(base, size); + // 特判第一个区域 + if inner.initial_memory_regions_num == 0 { + inner.initial_memory_regions[0] = block; + inner.initial_memory_regions_num += 1; + return Ok(()); + } + + // 先计算需要添加的区域数量 + let blocks_to_add = self + .do_add_block(&mut inner, block, false) + .expect("Failed to count blocks to add!"); + + if inner.initial_memory_regions_num + blocks_to_add > INITIAL_MEMORY_REGIONS_NUM { + kerror!("Too many memory regions!"); + return Err(SystemError::ENOMEM); + } + + // 然后添加区域 + self.do_add_block(&mut inner, block, true) + .expect("Failed to add block!"); + + return Ok(()); + } + + fn do_add_block( + &self, + inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, + block: PhysMemoryArea, + insert: bool, + ) -> Result { + let mut base = block.base; + let end = block.base + block.size; + let mut i = 0; + let mut start_index = -1; + let mut end_index = -1; + + let mut num_to_add = 0; + + while i < inner.initial_memory_regions_num { + let range_base = inner.initial_memory_regions[i].base; + let range_end = + inner.initial_memory_regions[i].base + inner.initial_memory_regions[i].size; + + if range_base >= end { + break; + } + if range_end <= base { + i += 1; + continue; + } + + // 有重叠 + + if range_base > base { + num_to_add += 1; + if insert { + if start_index == -1 { + start_index = i as isize; + } + end_index = (i + 1) as isize; + self.do_insert_area(inner, i, base, range_base - base); + i += 1; + } + } + + i += 1; + base = core::cmp::min(range_end, end); + } + + if base < end { + num_to_add += 1; + if insert { + if start_index == -1 { + start_index = i as isize; + } + end_index = (i + 1) as isize; + self.do_insert_area(inner, i, base, end - base); + } + } + + if num_to_add == 0 { + return Ok(0); + } + + if insert { + self.do_merge_blocks(inner, start_index, end_index); + } + return Ok(num_to_add); + } + + fn do_insert_area( + &self, + inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, + index: usize, + base: PhysAddr, + size: usize, + ) { + let copy_elements = inner.initial_memory_regions_num - index; + inner + .initial_memory_regions + .copy_within(index..index + copy_elements, index + 1); + inner.initial_memory_regions[index] = PhysMemoryArea::new(base, size); + inner.initial_memory_regions_num += 1; + } + + fn do_merge_blocks( + &self, + inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, + start_index: isize, + mut end_index: isize, + ) { + let mut i = 0; + if start_index > 0 { + i = start_index - 1; + } + end_index = core::cmp::min(end_index, inner.initial_memory_regions_num as isize - 1); + + while i < end_index { + { + let next_base = inner.initial_memory_regions[(i + 1) as usize].base; + let next_size = inner.initial_memory_regions[(i + 1) as usize].size; + let this = &mut inner.initial_memory_regions[i as usize]; + + if this.base + this.size != next_base { + // BUG_ON(this->base + this->size > next->base); + i += 1; + continue; + } + this.size += next_size; + } + // 移动后面的区域 + let copy_elements = inner.initial_memory_regions_num - (i + 2) as usize; + inner.initial_memory_regions.copy_within( + (i + 2) as usize..(i as usize + 2 + copy_elements), + (i + 1) as usize, + ); + + inner.initial_memory_regions_num -= 1; + end_index -= 1; + } + } + + /// 移除内存区域 + /// + /// 如果移除的区域与已有区域有重叠,会将重叠的区域分割 + #[allow(dead_code)] + pub fn remove_block(&self, base: PhysAddr, size: usize) -> Result<(), SystemError> { + if size == 0 { + return Ok(()); + } + let mut inner = self.inner.lock(); + if inner.initial_memory_regions_num == 0 { + return Ok(()); + } + + let (start_index, end_index) = self + .isolate_range(&mut inner, base, size) + .expect("Failed to isolate range!"); + + for i in (start_index..end_index).rev() { + self.do_remove_region(&mut inner, i); + } + return Ok(()); + } + + fn do_remove_region(&self, inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, index: usize) { + let copy_elements = inner.initial_memory_regions_num - index - 1; + inner + .initial_memory_regions + .copy_within(index + 1..index + 1 + copy_elements, index); + + inner.initial_memory_regions_num -= 1; + + if inner.initial_memory_regions_num == 0 { + inner.initial_memory_regions[0].base = PhysAddr::new(0); + inner.initial_memory_regions[0].size = 0; + } + } + + fn isolate_range( + &self, + inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, + base: PhysAddr, + size: usize, + ) -> Result<(usize, usize), SystemError> { + let end = base + size; + + let mut idx = 0; + + let mut start_index = 0; + let mut end_index = 0; + + if size == 0 { + return Ok((0, 0)); + } + + while idx < inner.initial_memory_regions_num { + let range_base = inner.initial_memory_regions[idx].base; + let range_end = range_base + inner.initial_memory_regions[idx].size; + + if range_base >= end { + break; + } + if range_end <= base { + idx = idx.checked_add(1).unwrap_or(0); + continue; + } + + if range_base < base { + // regions[idx] intersects from below + inner.initial_memory_regions[idx].base = base; + inner.initial_memory_regions[idx].size -= base - range_base; + self.do_insert_area(inner, idx, range_base, base - range_base); + } else if range_end > end { + // regions[idx] intersects from above + inner.initial_memory_regions[idx].base = end; + inner.initial_memory_regions[idx].size -= end - range_base; + + self.do_insert_area(inner, idx, range_base, end - range_base); + if idx == 0 { + idx = usize::MAX; + } else { + idx -= 1; + } + } else { + // regions[idx] is inside the range, record it + if end_index == 0 { + start_index = idx; + } + end_index = idx + 1; + } + + idx = idx.checked_add(1).unwrap_or(0); + } + + return Ok((start_index, end_index)); + } + + /// 生成迭代器 + pub fn to_iter(&self) -> MemBlockIter { + let inner = self.inner.lock(); + return MemBlockIter { inner, index: 0 }; + } + + /// 获取初始内存区域数量 + pub fn total_initial_memory_regions(&self) -> usize { + let inner = self.inner.lock(); + return inner.initial_memory_regions_num; + } + + /// 根据索引获取初始内存区域 + pub fn get_initial_memory_region(&self, index: usize) -> Option { + let inner = self.inner.lock(); + return inner.initial_memory_regions.get(index).copied(); + } +} + +pub struct MemBlockIter<'a> { + inner: SpinLockGuard<'a, InnerMemBlockManager>, + index: usize, +} + +#[allow(dead_code)] +impl<'a> MemBlockIter<'a> { + /// 获取内存区域数量 + pub fn total_num(&self) -> usize { + self.inner.initial_memory_regions_num + } + + /// 获取指定索引的内存区域 + pub fn get_area(&self, index: usize) -> &PhysMemoryArea { + &self.inner.initial_memory_regions[index] + } + + /// 获取当前索引 + pub fn current_index(&self) -> usize { + self.index + } +} + +impl<'a> Iterator for MemBlockIter<'a> { + type Item = PhysMemoryArea; + + fn next(&mut self) -> Option { + if self.index >= self.inner.initial_memory_regions_num { + return None; + } + let ret = self.inner.initial_memory_regions[self.index]; + self.index += 1; + return Some(ret); + } +} diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 9d1db25a..97aaa363 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -21,6 +21,7 @@ use self::{ pub mod allocator; pub mod c_adapter; pub mod kernel_mapper; +pub mod memblock; pub mod mmio_buddy; pub mod no_init; pub mod page; @@ -331,6 +332,11 @@ pub struct PhysMemoryArea { } impl PhysMemoryArea { + pub const DEFAULT: Self = Self { + base: PhysAddr::new(0), + size: 0, + }; + pub fn new(base: PhysAddr, size: usize) -> Self { Self { base, size } } @@ -350,10 +356,7 @@ impl PhysMemoryArea { impl Default for PhysMemoryArea { fn default() -> Self { - Self { - base: PhysAddr::new(0), - size: 0, - } + return Self::DEFAULT; } } @@ -427,8 +430,8 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { const USER_STACK_START: VirtAddr; /// @brief 用于初始化内存管理模块与架构相关的信息。 - /// 该函数应调用其他模块的接口,生成内存区域结构体,提供给BumpAllocator使用 - unsafe fn init() -> &'static [PhysMemoryArea]; + /// 该函数应调用其他模块的接口,把可用内存区域添加到memblock,提供给BumpAllocator使用 + unsafe fn init(); /// @brief 读取指定虚拟地址的值,并假设它是类型T的指针 #[inline(always)] diff --git a/kernel/submodules/DragonStub b/kernel/submodules/DragonStub index 5d9a3c15..7fc3806d 160000 --- a/kernel/submodules/DragonStub +++ b/kernel/submodules/DragonStub @@ -1 +1 @@ -Subproject commit 5d9a3c158772e628967d96e442c7398fa9da576a +Subproject commit 7fc3806da73be059540a79b6fdddf8049be250f3