Browse Source

riscv: 解析dtb,获取可用内存空间并添加到memblock (#486)

LoGin 1 year ago
parent
commit
45626c859f

+ 6 - 0
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" }

+ 56 - 1
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.");
+}

+ 1 - 1
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!()
     }
 

+ 1 - 1
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;

+ 6 - 0
kernel/src/arch/x86_64/init/mod.rs

@@ -0,0 +1,6 @@
+#[derive(Debug)]
+pub struct ArchBootParams {}
+
+impl ArchBootParams {
+    pub const DEFAULT: Self = ArchBootParams {};
+}

+ 4 - 5
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<MMA: MemoryManagementArch> BumpAllocator<MMA> {
     pub unsafe fn arch_remain_areas(
@@ -23,7 +23,7 @@ impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
         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<MMA: MemoryManagementArch> BumpAllocator<MMA> {
             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;
         }
 

+ 26 - 19
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<crate::arch::x86_64::mm::X86_64MMArch, LockedFrameAllocator>;
 
-/// @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::<X86_64MMArch>::new(&PHYS_MEMORY_AREAS, phy_offset.data());
+    let mut bump_allocator = BumpAllocator::<X86_64MMArch>::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);

+ 1 - 0
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;

+ 1 - 0
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;

+ 300 - 0
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<FdtGlobalData> = 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<VirtAddr> = 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<NodeProperty<'_>> = 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(())
+    }
+}

+ 2 - 0
kernel/src/driver/open_firmware/mod.rs

@@ -0,0 +1,2 @@
+#[cfg(target_arch = "riscv64")]
+pub mod fdt;

+ 56 - 0
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<usize> = 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;
+    }
 }

+ 16 - 16
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<MMA> {
-    // 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。
-    areas: &'static [PhysMemoryArea],
     // 表示当前分配的物理内存的偏移量.
     offset: usize,
     // 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
@@ -22,17 +20,13 @@ impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
     /// @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<MMA: MemoryManagementArch> BumpAllocator<MMA> {
 
         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<MMA: MemoryManagementArch> BumpAllocator<MMA> {
             }
             // 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<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
     /// @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<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
     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对齐,对其时向下取整

+ 351 - 0
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<InnerMemBlockManager>,
+}
+
+#[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<usize, SystemError> {
+        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<PhysMemoryArea> {
+        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<Self::Item> {
+        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);
+    }
+}

+ 9 - 6
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)]

+ 1 - 1
kernel/submodules/DragonStub

@@ -1 +1 @@
-Subproject commit 5d9a3c158772e628967d96e442c7398fa9da576a
+Subproject commit 7fc3806da73be059540a79b6fdddf8049be250f3