新的内存管理模块 (#301)

  实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。

  内存管理模块主要由以下类型的组件组成:

- **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行
- **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中)
- **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新)
- **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator
- **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成)
- **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构)
- **用户地址空间管理机制** - 提供对用户地址空间的管理。
    - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作
    - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射
- **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等
- **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。


除上面的新增内容以外,其它的更改内容:
- 新增二进制加载器,以及elf的解析器
- 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。
- 解决local_irq_save未关中断的错误。
- 修复sys_gettimeofday对timezone参数的处理的bug
This commit is contained in:
LoGin
2023-07-22 16:22:17 +08:00
committed by GitHub
parent 0663027b11
commit d8ad0a5e77
124 changed files with 8277 additions and 5150 deletions

View File

@ -1,43 +1,219 @@
use core::intrinsics::unlikely;
use alloc::sync::Arc;
use crate::{
include::bindings::bindings::mm_stat_t,
arch::MMArch,
kerror,
libs::align::{check_aligned, page_align_up},
mm::MemoryManagementArch,
syscall::{Syscall, SystemError},
};
extern "C" {
fn sys_do_brk(new_addr: usize) -> usize;
fn sys_do_sbrk(incr: isize) -> usize;
fn sys_do_mstat(dst: *mut mm_stat_t, from_user: bool) -> usize;
use super::{
allocator::page_frame::{PageFrameCount, VirtPageFrame},
ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
verify_area, VirtAddr,
};
bitflags! {
/// Memory protection flags
pub struct ProtFlags: u64 {
const PROT_NONE = 0x0;
const PROT_READ = 0x1;
const PROT_WRITE = 0x2;
const PROT_EXEC = 0x4;
}
/// Memory mapping flags
pub struct MapFlags: u64 {
const MAP_NONE = 0x0;
/// share changes
const MAP_SHARED = 0x1;
/// changes are private
const MAP_PRIVATE = 0x2;
/// Interpret addr exactly
const MAP_FIXED = 0x10;
/// don't use a file
const MAP_ANONYMOUS = 0x20;
// linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
/// stack-like segment
const MAP_GROWSDOWN = 0x100;
/// ETXTBSY
const MAP_DENYWRITE = 0x800;
/// Mark it as an executable
const MAP_EXECUTABLE = 0x1000;
/// Pages are locked
const MAP_LOCKED = 0x2000;
/// don't check for reservations
const MAP_NORESERVE = 0x4000;
/// populate (prefault) pagetables
const MAP_POPULATE = 0x8000;
/// do not block on IO
const MAP_NONBLOCK = 0x10000;
/// give out an address that is best suited for process/thread stacks
const MAP_STACK = 0x20000;
/// create a huge page mapping
const MAP_HUGETLB = 0x40000;
/// perform synchronous page faults for the mapping
const MAP_SYNC = 0x80000;
/// MAP_FIXED which doesn't unmap underlying mapping
const MAP_FIXED_NOREPLACE = 0x100000;
/// For anonymous mmap, memory could be uninitialized
const MAP_UNINITIALIZED = 0x4000000;
}
}
impl Syscall {
pub fn brk(new_addr: usize) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_brk(new_addr) };
if (ret as isize) < 0 {
return Err(
SystemError::from_posix_errno(-(ret as isize) as i32).expect("brk: Invalid errno")
);
pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
// kdebug!("brk: new_addr={:?}", new_addr);
let address_space = AddressSpace::current()?;
let mut address_space = address_space.write();
unsafe {
address_space
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))
.ok();
return Ok(address_space.sbrk(0).unwrap());
}
return Ok(ret);
}
pub fn sbrk(incr: isize) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_sbrk(incr) };
if (ret as isize) < 0 {
return Err(
SystemError::from_posix_errno(-(ret as isize) as i32).expect("sbrk: Invalid errno")
);
}
return Ok(ret);
pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
// kdebug!("pid:{}, sbrk: incr={}", current_pcb().pid, incr);
let address_space = AddressSpace::current()?;
let mut address_space = address_space.write();
let r = unsafe { address_space.sbrk(incr) };
// kdebug!("pid:{}, sbrk: r={:?}", current_pcb().pid, r);
return r;
}
/// 获取内存统计信息
/// ## mmap系统调用
///
/// TODO: 该函数不是符合POSIX标准的在将来需要删除
pub fn mstat(dst: *mut mm_stat_t, from_user: bool) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_mstat(dst, from_user) };
if (ret as isize) < 0 {
return Err(SystemError::from_posix_errno(-(ret as isize) as i32)
.expect("mstat: Invalid errno"));
/// 该函数的实现参考了Linux内核的实现但是并不完全相同。因为有些功能咱们还没实现
///
/// ## 参数
///
/// - `start_vaddr`:映射的起始地址
/// - `len`:映射的长度
/// - `prot`:保护标志
/// - `flags`:映射标志
/// - `fd`:文件描述符(暂时不支持)
/// - `offset`:文件偏移量 (暂时不支持)
///
/// ## 返回值
///
/// 成功时返回映射的起始地址,失败时返回错误码
pub fn mmap(
start_vaddr: VirtAddr,
len: usize,
prot_flags: usize,
map_flags: usize,
_fd: i32,
_offset: usize,
) -> Result<usize, SystemError> {
let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
&& map_flags.contains(MapFlags::MAP_FIXED)
{
kerror!(
"mmap: MAP_FIXED is not supported for address below {}",
DEFAULT_MMAP_MIN_ADDR
);
return Err(SystemError::EINVAL);
}
return Ok(ret);
// 暂时不支持除匿名页以外的映射
if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
kerror!("mmap: not support file mapping");
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 暂时不支持巨页映射
if map_flags.contains(MapFlags::MAP_HUGETLB) {
kerror!("mmap: not support huge page mapping");
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
let current_address_space = AddressSpace::current()?;
let start_page = current_address_space.write().map_anonymous(
start_vaddr,
len,
prot_flags,
map_flags,
true,
)?;
return Ok(start_page.virt_address().data());
}
/// ## munmap系统调用
///
/// ## 参数
///
/// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
/// - `len`:取消映射的字节数(已经对齐到页)
///
/// ## 返回值
///
/// 成功时返回0失败时返回错误码
pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(check_aligned(len, MMArch::PAGE_SIZE));
if unlikely(verify_area(start_vaddr, len).is_err()) {
return Err(SystemError::EINVAL);
}
if unlikely(len == 0) {
return Err(SystemError::EINVAL);
}
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
let start_frame = VirtPageFrame::new(start_vaddr);
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
current_address_space
.write()
.munmap(start_frame, page_count)
.map_err(|_| SystemError::EINVAL)?;
return Ok(0);
}
/// ## mprotect系统调用
///
/// ## 参数
///
/// - `start_vaddr`:起始地址(已经对齐到页)
/// - `len`:长度(已经对齐到页)
/// - `prot_flags`:保护标志
pub fn mprotect(
start_vaddr: VirtAddr,
len: usize,
prot_flags: usize,
) -> Result<usize, SystemError> {
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(check_aligned(len, MMArch::PAGE_SIZE));
if unlikely(verify_area(start_vaddr, len).is_err()) {
return Err(SystemError::EINVAL);
}
if unlikely(len == 0) {
return Err(SystemError::EINVAL);
}
let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
let start_frame = VirtPageFrame::new(start_vaddr);
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
current_address_space
.write()
.mprotect(start_frame, page_count, prot_flags)
.map_err(|_| SystemError::EINVAL)?;
return Ok(0);
}
}