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

This commit is contained in:
LoGin 2024-01-03 18:00:47 +08:00 committed by GitHub
parent 02343d0b5b
commit 45626c859f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 837 additions and 50 deletions

View File

@ -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" }

View File

@ -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.");
}

View File

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

View File

@ -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;

View File

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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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(())
}
}

View File

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

View File

@ -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;
}
}

View File

@ -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
kernel/src/mm/memblock.rs Normal file
View File

@ -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);
}
}

View File

@ -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 @@
Subproject commit 5d9a3c158772e628967d96e442c7398fa9da576a
Subproject commit 7fc3806da73be059540a79b6fdddf8049be250f3