mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-23 12:13:22 +00:00
新的内存管理模块 (#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:
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user