mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 20:36:31 +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:
@ -3,7 +3,7 @@
|
||||
|
||||
use core::{alloc::GlobalAlloc, fmt::Debug, ptr::Unique};
|
||||
|
||||
use crate::{syscall::SystemError, KERNEL_ALLOCATOR};
|
||||
use crate::{arch::MMArch, mm::MemoryManagementArch, syscall::SystemError, KERNEL_ALLOCATOR};
|
||||
|
||||
/// # AlignedBox
|
||||
///
|
||||
@ -112,3 +112,29 @@ impl<T: Clone + SafeForZero, const ALIGN: usize> Clone for AlignedBox<T, ALIGN>
|
||||
pub unsafe trait SafeForZero {}
|
||||
|
||||
unsafe impl<const NUM: usize> SafeForZero for [u8; NUM] {}
|
||||
|
||||
/// 将给定的地址按照页面大小,向上对齐。
|
||||
///
|
||||
/// 参数 `addr`:要对齐的地址。
|
||||
///
|
||||
/// 返回值:对齐后的地址。
|
||||
pub fn page_align_up(addr: usize) -> usize {
|
||||
let page_size = MMArch::PAGE_SIZE;
|
||||
return (addr + page_size - 1) & (!(page_size - 1));
|
||||
}
|
||||
|
||||
/// ## 检查是否对齐
|
||||
///
|
||||
/// 检查给定的值是否对齐到给定的对齐要求。
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `value`:要检查的值
|
||||
/// - `align`:对齐要求,必须是2的幂次方,且不为0,否则运行时panic
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 如果对齐则返回`true`,否则返回`false`
|
||||
pub fn check_aligned(value: usize, align: usize) -> bool {
|
||||
assert!(align != 0 && align.is_power_of_two());
|
||||
return value & (align - 1) == 0;
|
||||
}
|
||||
|
785
kernel/src/libs/elf.rs
Normal file
785
kernel/src/libs/elf.rs
Normal file
@ -0,0 +1,785 @@
|
||||
use core::{
|
||||
cmp::min,
|
||||
intrinsics::{likely, unlikely},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use elf::{endian::AnyEndian, file::FileHeader, segment::ProgramHeader};
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
current_pcb,
|
||||
io::SeekFrom,
|
||||
kerror,
|
||||
libs::align::page_align_up,
|
||||
mm::{
|
||||
allocator::page_frame::{PageFrameCount, VirtPageFrame},
|
||||
syscall::{MapFlags, ProtFlags},
|
||||
ucontext::InnerAddressSpace,
|
||||
MemoryManagementArch, VirtAddr,
|
||||
},
|
||||
process::{
|
||||
abi::AtType,
|
||||
exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam},
|
||||
},
|
||||
syscall::{
|
||||
user_access::{clear_user, copy_to_user},
|
||||
SystemError,
|
||||
},
|
||||
};
|
||||
|
||||
use super::rwlock::RwLockWriteGuard;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ElfLoader;
|
||||
|
||||
pub const ELF_LOADER: ElfLoader = ElfLoader::new();
|
||||
|
||||
impl ElfLoader {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub const ELF_PAGE_SIZE: usize = MMArch::PAGE_SIZE;
|
||||
|
||||
/// 读取文件的缓冲区大小
|
||||
pub const FILE_READ_BUF_SIZE: usize = 512 * 1024;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn probe_x86_64(
|
||||
&self,
|
||||
param: &ExecParam,
|
||||
ehdr: &FileHeader<AnyEndian>,
|
||||
) -> Result<(), ExecError> {
|
||||
// 只支持 64 位的 ELF 文件
|
||||
if ehdr.class != elf::file::Class::ELF64 {
|
||||
return Err(ExecError::WrongArchitecture);
|
||||
}
|
||||
|
||||
// 判断架构是否匹配
|
||||
if ElfMachine::from(ehdr.e_machine) != ElfMachine::X86_64 {
|
||||
return Err(ExecError::WrongArchitecture);
|
||||
}
|
||||
|
||||
// 判断是否以可执行文件的形式加载
|
||||
if param.load_mode() == ExecLoadMode::Exec {
|
||||
// 检查文件类型是否为可执行文件
|
||||
if ElfType::from(ehdr.e_type) != ElfType::Executable {
|
||||
return Err(ExecError::NotExecutable);
|
||||
}
|
||||
} else {
|
||||
return Err(ExecError::NotSupported);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 设置用户堆空间,映射[start, end)区间的虚拟地址,并把brk指针指向end
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `user_vm_guard` - 用户虚拟地址空间
|
||||
/// - `start` - 本次映射的起始地址
|
||||
/// - `end` - 本次映射的结束地址(不包含)
|
||||
/// - `prot_flags` - 本次映射的权限
|
||||
fn set_elf_brk(
|
||||
&self,
|
||||
user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>,
|
||||
start: VirtAddr,
|
||||
end: VirtAddr,
|
||||
prot_flags: ProtFlags,
|
||||
) -> Result<(), ExecError> {
|
||||
let start = self.elf_page_start(start);
|
||||
let end = self.elf_page_align_up(end);
|
||||
// kdebug!("set_elf_brk: start={:?}, end={:?}", start, end);
|
||||
if end > start {
|
||||
let r = user_vm_guard.map_anonymous(
|
||||
start,
|
||||
end - start,
|
||||
prot_flags,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE,
|
||||
false,
|
||||
);
|
||||
if r.is_err() {
|
||||
kerror!("set_elf_brk: map_anonymous failed, err={:?}", r);
|
||||
return Err(ExecError::OutOfMemory);
|
||||
}
|
||||
}
|
||||
user_vm_guard.elf_brk_start = end;
|
||||
user_vm_guard.elf_brk = end;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 计算addr在ELF PAGE内的偏移
|
||||
fn elf_page_offset(&self, addr: VirtAddr) -> usize {
|
||||
addr.data() & (Self::ELF_PAGE_SIZE - 1)
|
||||
}
|
||||
|
||||
fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr {
|
||||
VirtAddr::new(addr.data() & (!(Self::ELF_PAGE_SIZE - 1)))
|
||||
}
|
||||
|
||||
fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr {
|
||||
VirtAddr::new((addr.data() + Self::ELF_PAGE_SIZE - 1) & (!(Self::ELF_PAGE_SIZE - 1)))
|
||||
}
|
||||
|
||||
/// 根据ELF的p_flags生成对应的ProtFlags
|
||||
fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags {
|
||||
let mut prot = ProtFlags::empty();
|
||||
if p_flags & elf::abi::PF_R != 0 {
|
||||
prot |= ProtFlags::PROT_READ;
|
||||
}
|
||||
if p_flags & elf::abi::PF_W != 0 {
|
||||
prot |= ProtFlags::PROT_WRITE;
|
||||
}
|
||||
if p_flags & elf::abi::PF_X != 0 {
|
||||
prot |= ProtFlags::PROT_EXEC;
|
||||
}
|
||||
|
||||
// todo: 增加与架构相关的处理
|
||||
// ref: https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#572
|
||||
|
||||
return prot;
|
||||
}
|
||||
|
||||
/// 加载ELF文件到用户空间
|
||||
///
|
||||
/// 参考Linux的elf_map函数
|
||||
/// https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#365
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `user_vm_guard`:用户空间地址空间
|
||||
/// - `param`:执行参数
|
||||
/// - `phent`:ELF文件的ProgramHeader
|
||||
/// - `addr_to_map`:当前段应该被加载到的内存地址
|
||||
/// - `prot`:保护标志
|
||||
/// - `map_flags`:映射标志
|
||||
/// - `total_size`:ELF文件的总大小
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址
|
||||
fn load_elf_segment(
|
||||
&self,
|
||||
user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>,
|
||||
param: &mut ExecParam,
|
||||
phent: &ProgramHeader,
|
||||
mut addr_to_map: VirtAddr,
|
||||
prot: &ProtFlags,
|
||||
map_flags: &MapFlags,
|
||||
total_size: usize,
|
||||
) -> Result<(VirtAddr, bool), SystemError> {
|
||||
// kdebug!("load_elf_segment: addr_to_map={:?}", addr_to_map);
|
||||
|
||||
// 映射位置的偏移量(页内偏移)
|
||||
let beginning_page_offset = self.elf_page_offset(addr_to_map);
|
||||
addr_to_map = self.elf_page_start(addr_to_map);
|
||||
// 计算要映射的内存的大小
|
||||
let map_size = phent.p_filesz as usize
|
||||
+ self.elf_page_offset(VirtAddr::new(phent.p_vaddr as usize))
|
||||
+ beginning_page_offset;
|
||||
let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data();
|
||||
// 当前段在文件中的大小
|
||||
let seg_in_file_size = phent.p_filesz as usize;
|
||||
// 当前段在文件中的偏移量
|
||||
let file_offset = phent.p_offset as usize;
|
||||
|
||||
// 如果当前段的大小为0,则直接返回.
|
||||
// 段在文件中的大小为0,是合法的,但是段在内存中的大小不能为0
|
||||
if map_size == 0 {
|
||||
return Ok((addr_to_map, true));
|
||||
}
|
||||
|
||||
let map_err_handler = |err: SystemError| {
|
||||
if err == SystemError::EEXIST {
|
||||
kerror!(
|
||||
"Pid: {}, elf segment at {:p} overlaps with existing mapping",
|
||||
current_pcb().pid,
|
||||
addr_to_map.as_ptr::<u8>()
|
||||
);
|
||||
}
|
||||
err
|
||||
};
|
||||
// 由于后面需要把ELF文件的内容加载到内存,因此暂时把当前段的权限设置为可写
|
||||
let tmp_prot = if !prot.contains(ProtFlags::PROT_WRITE) {
|
||||
*prot | ProtFlags::PROT_WRITE
|
||||
} else {
|
||||
*prot
|
||||
};
|
||||
|
||||
// 映射到的虚拟地址。请注意,这个虚拟地址是user_vm_guard这个地址空间的虚拟地址。不一定是当前进程地址空间的
|
||||
let map_addr: VirtAddr;
|
||||
|
||||
// total_size is the size of the ELF (interpreter) image.
|
||||
// The _first_ mmap needs to know the full size, otherwise
|
||||
// randomization might put this image into an overlapping
|
||||
// position with the ELF binary image. (since size < total_size)
|
||||
// So we first map the 'big' image - and unmap the remainder at
|
||||
// the end. (which unmap is needed for ELF images with holes.)
|
||||
if total_size != 0 {
|
||||
let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data();
|
||||
|
||||
// kdebug!("total_size={}", total_size);
|
||||
|
||||
map_addr = user_vm_guard
|
||||
.map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false)
|
||||
.map_err(map_err_handler)?
|
||||
.virt_address();
|
||||
// kdebug!("map ok: addr_to_map={:?}", addr_to_map);
|
||||
|
||||
let to_unmap = map_addr + map_size;
|
||||
let to_unmap_size = total_size - map_size;
|
||||
|
||||
// kdebug!("to_unmap={:?}, to_unmap_size={}", to_unmap, to_unmap_size);
|
||||
user_vm_guard.munmap(
|
||||
VirtPageFrame::new(to_unmap),
|
||||
PageFrameCount::from_bytes(to_unmap_size).unwrap(),
|
||||
)?;
|
||||
|
||||
// 加载文件到内存
|
||||
self.do_load_file(
|
||||
map_addr + beginning_page_offset,
|
||||
seg_in_file_size,
|
||||
file_offset,
|
||||
param,
|
||||
)?;
|
||||
if tmp_prot != *prot {
|
||||
user_vm_guard.mprotect(
|
||||
VirtPageFrame::new(map_addr),
|
||||
PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(),
|
||||
*prot,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
// kdebug!("total size = 0");
|
||||
|
||||
map_addr = user_vm_guard
|
||||
.map_anonymous(addr_to_map, map_size, tmp_prot, *map_flags, false)?
|
||||
.virt_address();
|
||||
// kdebug!(
|
||||
// "map ok: addr_to_map={:?}, map_addr={map_addr:?},beginning_page_offset={beginning_page_offset:?}",
|
||||
// addr_to_map
|
||||
// );
|
||||
|
||||
// 加载文件到内存
|
||||
self.do_load_file(
|
||||
map_addr + beginning_page_offset,
|
||||
seg_in_file_size,
|
||||
file_offset,
|
||||
param,
|
||||
)?;
|
||||
|
||||
if tmp_prot != *prot {
|
||||
user_vm_guard.mprotect(
|
||||
VirtPageFrame::new(map_addr),
|
||||
PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(),
|
||||
*prot,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
// kdebug!("load_elf_segment OK: map_addr={:?}", map_addr);
|
||||
return Ok((map_addr, true));
|
||||
}
|
||||
|
||||
/// 加载ELF文件到用户空间
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `vaddr`:要加载到的虚拟地址
|
||||
/// - `size`:要加载的大小
|
||||
/// - `offset_in_file`:在文件内的偏移量
|
||||
/// - `param`:执行参数
|
||||
fn do_load_file(
|
||||
&self,
|
||||
mut vaddr: VirtAddr,
|
||||
size: usize,
|
||||
offset_in_file: usize,
|
||||
param: &mut ExecParam,
|
||||
) -> Result<(), SystemError> {
|
||||
let file = param.file_mut();
|
||||
if (file.metadata()?.size as usize) < offset_in_file + size {
|
||||
return Err(SystemError::ENOEXEC);
|
||||
}
|
||||
let buf_size = min(size, Self::FILE_READ_BUF_SIZE);
|
||||
let mut buf = vec![0u8; buf_size];
|
||||
|
||||
let mut remain = size;
|
||||
|
||||
file.lseek(SeekFrom::SeekSet(offset_in_file as i64))?;
|
||||
|
||||
while remain > 0 {
|
||||
let read_size = min(remain, buf_size);
|
||||
file.read(read_size, &mut buf[..read_size])?;
|
||||
// kdebug!("copy_to_user: vaddr={:?}, read_size = {read_size}", vaddr);
|
||||
unsafe {
|
||||
copy_to_user(vaddr, &buf[..read_size]).map_err(|_| SystemError::EFAULT)?;
|
||||
}
|
||||
|
||||
vaddr += read_size;
|
||||
remain -= read_size;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 我们需要显式的把数据段之后剩余的内存页都清零。
|
||||
fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> {
|
||||
let nbyte = self.elf_page_offset(elf_bss);
|
||||
if nbyte > 0 {
|
||||
let nbyte = Self::ELF_PAGE_SIZE - nbyte;
|
||||
unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 创建auxv
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `param`:执行参数
|
||||
/// - `entrypoint_vaddr`:程序入口地址
|
||||
/// - `phdr_vaddr`:程序头表地址
|
||||
/// - `elf_header`:ELF文件头
|
||||
fn create_auxv(
|
||||
&self,
|
||||
param: &mut ExecParam,
|
||||
entrypoint_vaddr: VirtAddr,
|
||||
phdr_vaddr: Option<VirtAddr>,
|
||||
ehdr: &elf::file::FileHeader<AnyEndian>,
|
||||
) -> Result<(), ExecError> {
|
||||
let phdr_vaddr = phdr_vaddr.unwrap_or(VirtAddr::new(0));
|
||||
|
||||
let init_info = param.init_info_mut();
|
||||
init_info
|
||||
.auxv
|
||||
.insert(AtType::PhEnt as u8, ehdr.e_phentsize as usize);
|
||||
init_info
|
||||
.auxv
|
||||
.insert(AtType::PageSize as u8, MMArch::PAGE_SIZE);
|
||||
init_info.auxv.insert(AtType::Phdr as u8, phdr_vaddr.data());
|
||||
init_info
|
||||
.auxv
|
||||
.insert(AtType::PhNum as u8, ehdr.e_phnum as usize);
|
||||
init_info
|
||||
.auxv
|
||||
.insert(AtType::Entry as u8, entrypoint_vaddr.data());
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 解析文件的ehdr
|
||||
fn parse_ehdr(data: &[u8]) -> Result<FileHeader<AnyEndian>, elf::ParseError> {
|
||||
let ident_buf = data.get_bytes(0..elf::abi::EI_NIDENT)?;
|
||||
let ident = elf::file::parse_ident::<AnyEndian>(ident_buf)?;
|
||||
|
||||
let tail_start = elf::abi::EI_NIDENT;
|
||||
let tail_end = match ident.1 {
|
||||
elf::file::Class::ELF32 => tail_start + elf::file::ELF32_EHDR_TAILSIZE,
|
||||
elf::file::Class::ELF64 => tail_start + elf::file::ELF64_EHDR_TAILSIZE,
|
||||
};
|
||||
let tail_buf = data.get_bytes(tail_start..tail_end)?;
|
||||
|
||||
let ehdr: FileHeader<_> = FileHeader::parse_tail(ident, tail_buf)?;
|
||||
return Ok(ehdr);
|
||||
}
|
||||
|
||||
/// 解析文件的program header table
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `param`:执行参数
|
||||
/// - `ehdr`:文件头
|
||||
/// - `data_buf`:用于缓存SegmentTable的Vec。
|
||||
/// 这是因为SegmentTable的生命周期与data_buf一致。初始化这个Vec的大小为0即可。
|
||||
///
|
||||
/// ## 说明
|
||||
///
|
||||
/// 这个函数由elf库的`elf::elf_bytes::find_phdrs`修改而来。
|
||||
fn parse_segments<'a>(
|
||||
param: &mut ExecParam,
|
||||
ehdr: &FileHeader<AnyEndian>,
|
||||
data_buf: &'a mut Vec<u8>,
|
||||
) -> Result<Option<elf::segment::SegmentTable<'a, AnyEndian>>, elf::ParseError> {
|
||||
// It's Ok to have no program headers
|
||||
if ehdr.e_phoff == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
let file = param.file_mut();
|
||||
// If the number of segments is greater than or equal to PN_XNUM (0xffff),
|
||||
// e_phnum is set to PN_XNUM, and the actual number of program header table
|
||||
// entries is contained in the sh_info field of the section header at index 0.
|
||||
let mut phnum = ehdr.e_phnum as usize;
|
||||
if phnum == elf::abi::PN_XNUM as usize {
|
||||
let shoff: usize = ehdr.e_shoff.try_into()?;
|
||||
|
||||
// 从磁盘读取shdr的前2个entry
|
||||
file.lseek(SeekFrom::SeekSet(shoff as i64))
|
||||
.map_err(|_| elf::ParseError::BadOffset(shoff as u64))?;
|
||||
let shdr_buf_size = ehdr.e_shentsize * 2;
|
||||
let mut shdr_buf = vec![0u8; shdr_buf_size as usize];
|
||||
file.read(shdr_buf_size as usize, &mut shdr_buf)
|
||||
.map_err(|_| elf::ParseError::BadOffset(shoff as u64))?;
|
||||
|
||||
let mut offset = 0;
|
||||
let shdr0 = <elf::section::SectionHeader as elf::parse::ParseAt>::parse_at(
|
||||
ehdr.endianness,
|
||||
ehdr.class,
|
||||
&mut offset,
|
||||
&shdr_buf,
|
||||
)?;
|
||||
phnum = shdr0.sh_info.try_into()?;
|
||||
}
|
||||
|
||||
// Validate phentsize before trying to read the table so that we can error early for corrupted files
|
||||
let entsize = <ProgramHeader as elf::parse::ParseAt>::validate_entsize(
|
||||
ehdr.class,
|
||||
ehdr.e_phentsize as usize,
|
||||
)?;
|
||||
let phoff: usize = ehdr.e_phoff.try_into()?;
|
||||
let size = entsize
|
||||
.checked_mul(phnum)
|
||||
.ok_or(elf::ParseError::IntegerOverflow)?;
|
||||
phoff
|
||||
.checked_add(size)
|
||||
.ok_or(elf::ParseError::IntegerOverflow)?;
|
||||
|
||||
// 读取program header table
|
||||
|
||||
file.lseek(SeekFrom::SeekSet(phoff as i64))
|
||||
.map_err(|_| elf::ParseError::BadOffset(phoff as u64))?;
|
||||
data_buf.clear();
|
||||
data_buf.resize(size, 0);
|
||||
|
||||
file.read(size, data_buf)
|
||||
.expect("read program header table failed");
|
||||
let buf = data_buf.get_bytes(0..size)?;
|
||||
|
||||
return Ok(Some(elf::segment::SegmentTable::new(
|
||||
ehdr.endianness,
|
||||
ehdr.class,
|
||||
buf,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryLoader for ElfLoader {
|
||||
fn probe(self: &'static Self, param: &ExecParam, buf: &[u8]) -> Result<(), ExecError> {
|
||||
// let elf_bytes =
|
||||
// ElfBytes::<AnyEndian>::minimal_parse(buf).map_err(|_| ExecError::NotExecutable)?;
|
||||
|
||||
let ehdr = Self::parse_ehdr(buf).map_err(|_| ExecError::NotExecutable)?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return self.probe_x86_64(param, &ehdr);
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
unimplemented!("Unsupported architecture");
|
||||
}
|
||||
|
||||
fn load(
|
||||
self: &'static Self,
|
||||
param: &mut ExecParam,
|
||||
head_buf: &[u8],
|
||||
) -> Result<BinaryLoaderResult, ExecError> {
|
||||
// 解析elf文件头
|
||||
let ehdr = Self::parse_ehdr(head_buf).map_err(|_| ExecError::NotExecutable)?;
|
||||
|
||||
// 参考linux-5.19的load_elf_binary函数
|
||||
// https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#1034
|
||||
|
||||
let elf_type = ElfType::from(ehdr.e_type);
|
||||
// kdebug!("ehdr = {:?}", ehdr);
|
||||
|
||||
let binding = param.vm().clone();
|
||||
let mut user_vm = binding.write();
|
||||
|
||||
// todo: 增加对user stack上的内存是否具有可执行权限的处理(方法:寻找phdr里面的PT_GNU_STACK段)
|
||||
|
||||
// todo: 增加对动态链接的处理
|
||||
|
||||
// kdebug!("to parse segments");
|
||||
// 加载ELF文件并映射到用户空间
|
||||
let mut phdr_buf = Vec::new();
|
||||
let loadable_sections = Self::parse_segments(param, &ehdr, &mut phdr_buf)
|
||||
.map_err(|_| ExecError::ParseError)?
|
||||
.ok_or(ExecError::ParseError)?
|
||||
.iter()
|
||||
.filter(|seg| seg.p_type == elf::abi::PT_LOAD);
|
||||
|
||||
// kdebug!("loadable_sections = {:?}", loadable_sections);
|
||||
|
||||
let mut elf_brk = VirtAddr::new(0);
|
||||
let mut elf_bss = VirtAddr::new(0);
|
||||
let mut start_code: Option<VirtAddr> = None;
|
||||
let mut end_code: Option<VirtAddr> = None;
|
||||
let mut start_data: Option<VirtAddr> = None;
|
||||
let mut end_data: Option<VirtAddr> = None;
|
||||
|
||||
// 加载的时候的偏移量(这个偏移量在加载动态链接段的时候产生,由于还没有动态链接,因此暂时不可变。)
|
||||
// 请不要删除load_bias! 以免到时候写动态链接的时候忘记了。
|
||||
let load_bias = 0usize;
|
||||
let mut bss_prot_flags = ProtFlags::empty();
|
||||
// 是否是第一个加载的段
|
||||
let mut first_pt_load = true;
|
||||
// program header的虚拟地址
|
||||
let mut phdr_vaddr: Option<VirtAddr> = None;
|
||||
for seg_to_load in loadable_sections {
|
||||
// kdebug!("seg_to_load = {:?}", seg_to_load);
|
||||
if unlikely(elf_brk > elf_bss) {
|
||||
// kdebug!(
|
||||
// "to set brk, elf_brk = {:?}, elf_bss = {:?}",
|
||||
// elf_brk,
|
||||
// elf_bss
|
||||
// );
|
||||
self.set_elf_brk(
|
||||
&mut user_vm,
|
||||
elf_bss + load_bias,
|
||||
elf_brk + load_bias,
|
||||
bss_prot_flags,
|
||||
)?;
|
||||
let nbyte = self.elf_page_offset(elf_bss);
|
||||
if nbyte > 0 {
|
||||
let nbyte = min(Self::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss);
|
||||
unsafe {
|
||||
// This bss-zeroing can fail if the ELF file specifies odd protections.
|
||||
// So we don't check the return value.
|
||||
clear_user(elf_bss + load_bias, nbyte).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成ProtFlags.
|
||||
// TODO: 当有了动态链接之后,需要根据情况设置这里的has_interpreter
|
||||
let elf_prot_flags = self.make_prot(seg_to_load.p_flags, false, false);
|
||||
|
||||
let mut elf_map_flags = MapFlags::MAP_PRIVATE;
|
||||
|
||||
let vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize);
|
||||
|
||||
if !first_pt_load {
|
||||
elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE);
|
||||
} else if elf_type == ElfType::Executable {
|
||||
/*
|
||||
* This logic is run once for the first LOAD Program
|
||||
* Header for ET_EXEC binaries. No special handling
|
||||
* is needed.
|
||||
*/
|
||||
elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE);
|
||||
} else if elf_type == ElfType::DSO {
|
||||
// TODO: 支持动态链接
|
||||
unimplemented!("DragonOS currently does not support dynamic linking!");
|
||||
}
|
||||
|
||||
// 加载这个段到用户空间
|
||||
// todo: 引入动态链接后,这里的total_size要按照实际的填写,而不一定是0
|
||||
|
||||
let e = self
|
||||
.load_elf_segment(
|
||||
&mut user_vm,
|
||||
param,
|
||||
&seg_to_load,
|
||||
vaddr + load_bias,
|
||||
&elf_prot_flags,
|
||||
&elf_map_flags,
|
||||
0,
|
||||
)
|
||||
.map_err(|e| match e {
|
||||
SystemError::EFAULT => ExecError::BadAddress(None),
|
||||
SystemError::ENOMEM => ExecError::OutOfMemory,
|
||||
_ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)),
|
||||
})?;
|
||||
|
||||
// 如果地址不对,那么就报错
|
||||
if !e.1 {
|
||||
return Err(ExecError::BadAddress(Some(e.0)));
|
||||
}
|
||||
|
||||
if first_pt_load {
|
||||
first_pt_load = false;
|
||||
if elf_type == ElfType::DSO {
|
||||
// todo: 在这里增加对load_bias和reloc_func_desc的更新代码
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// kdebug!("seg_to_load.p_offset={}", seg_to_load.p_offset);
|
||||
// kdebug!("e_phoff={}", ehdr.e_phoff);
|
||||
// kdebug!("seg_to_load.p_filesz={}", seg_to_load.p_filesz);
|
||||
// Figure out which segment in the file contains the Program Header Table,
|
||||
// and map to the associated virtual address.
|
||||
if (seg_to_load.p_offset <= ehdr.e_phoff)
|
||||
&& (ehdr.e_phoff < (seg_to_load.p_offset + seg_to_load.p_filesz))
|
||||
{
|
||||
phdr_vaddr = Some(VirtAddr::new(
|
||||
(ehdr.e_phoff - seg_to_load.p_offset + seg_to_load.p_vaddr) as usize,
|
||||
));
|
||||
}
|
||||
|
||||
let p_vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize);
|
||||
if (seg_to_load.p_flags & elf::abi::PF_X) != 0 {
|
||||
if start_code.is_none() || start_code.as_ref().unwrap() > &p_vaddr {
|
||||
start_code = Some(p_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
if start_data.is_none()
|
||||
|| (start_data.is_some() && start_data.as_ref().unwrap() > &p_vaddr)
|
||||
{
|
||||
start_data = Some(p_vaddr);
|
||||
}
|
||||
|
||||
// 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错
|
||||
if !p_vaddr.check_user()
|
||||
|| seg_to_load.p_filesz > seg_to_load.p_memsz
|
||||
|| seg_to_load.p_memsz > MMArch::USER_END_VADDR.data() as u64
|
||||
{
|
||||
// kdebug!("ERR: p_vaddr={p_vaddr:?}");
|
||||
return Err(ExecError::InvalidParemeter);
|
||||
}
|
||||
|
||||
drop(p_vaddr);
|
||||
|
||||
// end vaddr of this segment(code+data+bss)
|
||||
let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new(
|
||||
(seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize,
|
||||
));
|
||||
|
||||
if seg_end_vaddr_f > elf_bss {
|
||||
elf_bss = seg_end_vaddr_f;
|
||||
}
|
||||
|
||||
if ((seg_to_load.p_flags & elf::abi::PF_X) != 0)
|
||||
&& (end_code.is_none()
|
||||
|| (end_code.is_some() && end_code.as_ref().unwrap() < &seg_end_vaddr_f))
|
||||
{
|
||||
end_code = Some(seg_end_vaddr_f);
|
||||
}
|
||||
|
||||
if end_data.is_none()
|
||||
|| (end_data.is_some() && end_data.as_ref().unwrap() < &seg_end_vaddr_f)
|
||||
{
|
||||
end_data = Some(seg_end_vaddr_f);
|
||||
}
|
||||
|
||||
drop(seg_end_vaddr_f);
|
||||
|
||||
let seg_end_vaddr = VirtAddr::new((seg_to_load.p_vaddr + seg_to_load.p_memsz) as usize);
|
||||
|
||||
if seg_end_vaddr > elf_brk {
|
||||
bss_prot_flags = elf_prot_flags;
|
||||
elf_brk = seg_end_vaddr;
|
||||
}
|
||||
}
|
||||
// kdebug!("elf load: phdr_vaddr={phdr_vaddr:?}");
|
||||
let program_entrypoint = VirtAddr::new(ehdr.e_entry as usize + load_bias);
|
||||
let phdr_vaddr = if phdr_vaddr.is_some() {
|
||||
Some(phdr_vaddr.unwrap() + load_bias)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
elf_bss += load_bias;
|
||||
elf_brk += load_bias;
|
||||
start_code = start_code.map(|v| v + load_bias);
|
||||
end_code = end_code.map(|v| v + load_bias);
|
||||
start_data = start_data.map(|v| v + load_bias);
|
||||
end_data = end_data.map(|v| v + load_bias);
|
||||
|
||||
// kdebug!(
|
||||
// "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}",
|
||||
// elf_bss,
|
||||
// elf_brk,
|
||||
// bss_prot_flags
|
||||
// );
|
||||
self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?;
|
||||
|
||||
if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) {
|
||||
// kdebug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}");
|
||||
return Err(ExecError::BadAddress(Some(elf_bss)));
|
||||
}
|
||||
// todo: 动态链接:增加加载interpreter的代码
|
||||
// kdebug!("to create auxv");
|
||||
|
||||
self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?;
|
||||
|
||||
// kdebug!("auxv create ok");
|
||||
user_vm.start_code = start_code.unwrap_or(VirtAddr::new(0));
|
||||
user_vm.end_code = end_code.unwrap_or(VirtAddr::new(0));
|
||||
user_vm.start_data = start_data.unwrap_or(VirtAddr::new(0));
|
||||
user_vm.end_data = end_data.unwrap_or(VirtAddr::new(0));
|
||||
|
||||
let result = BinaryLoaderResult::new(program_entrypoint);
|
||||
// kdebug!("elf load OK!!!");
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// Elf机器架构,对应于e_machine字段。在ABI中,以EM_开头的常量是e_machine字段的值。
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum ElfMachine {
|
||||
I386,
|
||||
AArch32,
|
||||
AArch64,
|
||||
X86_64,
|
||||
RiscV,
|
||||
/// 龙芯架构
|
||||
LoongArch,
|
||||
/// 未知架构
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<u16> for ElfMachine {
|
||||
fn from(machine: u16) -> Self {
|
||||
match machine {
|
||||
0x03 => Self::I386,
|
||||
0x28 => Self::AArch32,
|
||||
0xb7 => Self::AArch64,
|
||||
0x3e => Self::X86_64,
|
||||
0xf3 => Self::RiscV,
|
||||
0x102 => Self::LoongArch,
|
||||
// 未知架构
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Elf文件类型,对应于e_type字段。在ABI中,以ET_开头的常量是e_type字段的值。
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum ElfType {
|
||||
/// 可重定位文件
|
||||
Relocatable,
|
||||
/// 可执行文件
|
||||
Executable,
|
||||
/// 动态链接库
|
||||
DSO,
|
||||
/// 核心转储文件
|
||||
Core,
|
||||
/// 未知类型
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<u16> for ElfType {
|
||||
fn from(elf_type: u16) -> Self {
|
||||
match elf_type {
|
||||
0x01 => Self::Relocatable,
|
||||
0x02 => Self::Executable,
|
||||
0x03 => Self::DSO,
|
||||
0x04 => Self::Core,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple convenience extension trait to wrap get() with .ok_or(SliceReadError)
|
||||
trait ReadBytesExt<'data> {
|
||||
fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], elf::ParseError>;
|
||||
}
|
||||
impl<'data> ReadBytesExt<'data> for &'data [u8] {
|
||||
fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], elf::ParseError> {
|
||||
let start = range.start;
|
||||
let end = range.end;
|
||||
self.get(range)
|
||||
.ok_or(elf::ParseError::SliceReadError((start, end)))
|
||||
}
|
||||
}
|
@ -44,10 +44,10 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type)
|
||||
buf->width = video_frame_buffer_info.width;
|
||||
buf->size = video_frame_buffer_info.size;
|
||||
|
||||
struct Page *p = alloc_pages(ZONE_NORMAL, PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE, 0);
|
||||
if (p == NULL)
|
||||
void* buf_vaddr = kzalloc(video_frame_buffer_info.size, 0);
|
||||
if (buf_vaddr == NULL)
|
||||
goto failed;
|
||||
buf->vaddr = (uint64_t)phys_2_virt(p->addr_phys);
|
||||
buf->vaddr = buf_vaddr;
|
||||
return buf;
|
||||
failed:;
|
||||
kfree(buf);
|
||||
@ -74,7 +74,7 @@ static int __destroy_buffer(struct scm_buffer_info_t *buf)
|
||||
return -EINVAL;
|
||||
|
||||
// 释放内存页
|
||||
free_pages(Phy_to_2M_Page(virt_2_phys(buf->vaddr)), PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE);
|
||||
kfree((void*)buf->vaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -295,7 +295,35 @@ int scm_framework_enable(struct scm_ui_framework_t *ui)
|
||||
}
|
||||
else
|
||||
__current_framework = ui;
|
||||
ui->ui_ops->enable(NULL);
|
||||
spin_unlock(&scm_screen_own_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 禁用某个ui框架,将它的帧缓冲区从屏幕上移除
|
||||
*
|
||||
* @param ui 要禁用的ui框架
|
||||
* @return int 返回码
|
||||
*/
|
||||
int scm_framework_disable(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
if (ui->buf->vaddr == NULL)
|
||||
return -EINVAL;
|
||||
spin_lock(&scm_screen_own_lock);
|
||||
if (ui != __current_framework)
|
||||
return -EINVAL;
|
||||
int retval = 0;
|
||||
if (__scm_double_buffer_enabled == true)
|
||||
{
|
||||
retval = video_set_refresh_target(NULL);
|
||||
if (retval == 0)
|
||||
__current_framework = NULL;
|
||||
}
|
||||
else
|
||||
__current_framework = NULL;
|
||||
|
||||
ui->ui_ops->disable(NULL);
|
||||
spin_unlock(&scm_screen_own_lock);
|
||||
return retval;
|
||||
}
|
||||
@ -307,7 +335,7 @@ int scm_framework_enable(struct scm_ui_framework_t *ui)
|
||||
void scm_reinit()
|
||||
{
|
||||
scm_enable_alloc();
|
||||
video_reinitialize(false);
|
||||
// video_reinitialize(false);
|
||||
|
||||
// 遍历当前所有使用帧缓冲区的框架,更新地址
|
||||
// 逐个检查已经注册了的ui框架,将其缓冲区更改为双缓冲
|
||||
|
@ -115,4 +115,6 @@ int scm_enable_double_buffer();
|
||||
* @param ui 要启动的ui框架
|
||||
* @return int 返回码
|
||||
*/
|
||||
int scm_framework_enable(struct scm_ui_framework_t *ui);
|
||||
int scm_framework_enable(struct scm_ui_framework_t *ui);
|
||||
|
||||
int scm_framework_disable(struct scm_ui_framework_t *ui);
|
@ -21,6 +21,9 @@ static struct textui_private_info_t __private_info = {0};
|
||||
static struct List __windows_list;
|
||||
static spinlock_t change_lock;
|
||||
|
||||
// 用于标记是否允许输出到屏幕
|
||||
static atomic_t __put_window_enable_flag = {1};
|
||||
|
||||
/**
|
||||
* @brief 初始化window对象
|
||||
*
|
||||
@ -69,7 +72,7 @@ static int __textui_init_window(struct textui_window_t *window, uint8_t flags, u
|
||||
int textui_install_handler(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
// return printk_init(buf);
|
||||
c_uart_send_str(COM1, "textui_install_handler");
|
||||
c_uart_send_str(COM1, "textui_install_handler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -81,11 +84,14 @@ int textui_uninstall_handler(void *args)
|
||||
int textui_enable_handler(void *args)
|
||||
{
|
||||
c_uart_send_str(COM1, "textui_enable_handler\n");
|
||||
atomic_cmpxchg(&__put_window_enable_flag, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_disable_handler(void *args)
|
||||
{
|
||||
c_uart_send_str(COM1, "textui_disable_handler\n");
|
||||
atomic_set(&__put_window_enable_flag, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -215,6 +221,13 @@ int textui_putchar_window(struct textui_window_t *window, uint16_t character, ui
|
||||
// uint64_t rflags = 0; // 加锁后rflags存储到这里
|
||||
spin_lock_no_preempt(&window->lock);
|
||||
c_uart_send(COM1, character);
|
||||
// 如果禁止输出,直接返回
|
||||
if(atomic_read(&__put_window_enable_flag) == 0)
|
||||
{
|
||||
spin_unlock_no_preempt(&window->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(character == '\n'))
|
||||
{
|
||||
// 换行时还需要输出\r
|
||||
@ -346,3 +359,14 @@ int textui_init()
|
||||
c_uart_send_str(COM1, "text ui initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void enable_textui()
|
||||
{
|
||||
scm_framework_enable(&textui_framework);
|
||||
}
|
||||
|
||||
void disable_textui()
|
||||
{
|
||||
scm_framework_disable(&textui_framework);
|
||||
}
|
@ -180,4 +180,8 @@ uint32_t __textui_get_current_window_id();
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int textui_init();
|
||||
int textui_init();
|
||||
|
||||
void enable_textui();
|
||||
|
||||
void disable_textui();
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod align;
|
||||
pub mod atomic;
|
||||
pub mod casting;
|
||||
pub mod elf;
|
||||
pub mod ffi_convert;
|
||||
#[macro_use]
|
||||
pub mod int_like;
|
||||
|
@ -594,7 +594,9 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
|
||||
int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
|
||||
{
|
||||
uint64_t rflags;
|
||||
io_mfence();
|
||||
spin_lock_irqsave(&__printk_lock, rflags);
|
||||
io_mfence();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buf[4096]; // vsprintf()的缓冲区
|
||||
@ -610,7 +612,9 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
|
||||
// 输出
|
||||
textui_putchar(current, FRcolor, BKcolor);
|
||||
}
|
||||
io_mfence();
|
||||
spin_unlock_irqrestore(&__printk_lock, rflags);
|
||||
io_mfence();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,15 @@
|
||||
#![allow(unused)]
|
||||
use crate::include::bindings::bindings::{printk_color, BLACK, WHITE};
|
||||
use crate::{
|
||||
driver::uart::uart::c_uart_send_str,
|
||||
include::bindings::bindings::{printk_color, BLACK, WHITE},
|
||||
};
|
||||
use ::core::ffi::c_char;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use core::{
|
||||
fmt::{self, Write},
|
||||
intrinsics::{likely, unlikely},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
// ====== 定义颜色 ======
|
||||
/// 白色
|
||||
@ -52,15 +59,15 @@ macro_rules! printk_color {
|
||||
#[macro_export]
|
||||
macro_rules! kdebug {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string((alloc::fmt::format(format_args!("[ DEBUG ] ({}:{})\t", file!(), line!()))+
|
||||
alloc::fmt::format(format_args!($($arg)*)).as_str() + "\n").as_str())
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("[ DEBUG ] ({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! kinfo {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string((alloc::string::String::from("[ INFO ] ")+ alloc::fmt::format(format_args!($($arg)*)).as_str() + "\n").as_str())
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("[ INFO ] ({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +75,7 @@ macro_rules! kinfo {
|
||||
macro_rules! kwarn {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_YELLOW, $crate::libs::printk::COLOR_BLACK, "[ WARN ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string((alloc::fmt::format(format_args!($($arg)*)) + "\n").as_str())
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,8 +83,7 @@ macro_rules! kwarn {
|
||||
macro_rules! kerror {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ ERROR ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string((alloc::fmt::format(format_args!("({}:{})\t", file!(), line!())) +
|
||||
alloc::fmt::format(format_args!($($arg)*)).as_str() + "\n").as_str())
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,17 +91,29 @@ macro_rules! kerror {
|
||||
macro_rules! kBUG {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ BUG ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string((alloc::fmt::format(format_args!("({}:{})\t", file!(), line!())) +
|
||||
alloc::fmt::format(format_args!($($arg)*)).as_str() + "\n").as_str())
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrintkWriter;
|
||||
|
||||
/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
|
||||
static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
|
||||
static mut ALLOW_ALLOC_BOOL: bool = false;
|
||||
|
||||
impl PrintkWriter {
|
||||
#[inline]
|
||||
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
|
||||
self.write_fmt(args);
|
||||
}
|
||||
|
||||
/// 调用C语言编写的printk_color,并输出白底黑字(暂时只支持ascii字符)
|
||||
/// @param str: 要写入的字符
|
||||
pub fn __write_string(&mut self, s: &str) {
|
||||
if unlikely(!self.allow_alloc()) {
|
||||
self.__write_string_on_stack(s);
|
||||
return;
|
||||
}
|
||||
let str_to_print = self.__utf8_to_ascii(s);
|
||||
unsafe {
|
||||
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
|
||||
@ -103,12 +121,36 @@ impl PrintkWriter {
|
||||
}
|
||||
|
||||
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
|
||||
if unlikely(!self.allow_alloc()) {
|
||||
self.__write_string_on_stack(s);
|
||||
return;
|
||||
}
|
||||
|
||||
let str_to_print = self.__utf8_to_ascii(s);
|
||||
unsafe {
|
||||
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn allow_alloc(&self) -> bool {
|
||||
// 由于allow_alloc只可能由false变为true
|
||||
// 因此采用两种方式读取它,一种是原子操作,一种是普通的bool,以优化性能。
|
||||
if likely(unsafe { ALLOW_ALLOC_BOOL }) {
|
||||
return true;
|
||||
} else {
|
||||
return ALLOW_ALLOC_ATOMIC.load(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
/// 允许动态内存分配
|
||||
pub fn enable_alloc(&self) {
|
||||
ALLOW_ALLOC_ATOMIC.store(true, Ordering::SeqCst);
|
||||
unsafe {
|
||||
ALLOW_ALLOC_BOOL = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// 将s这个utf8字符串,转换为ascii字符串
|
||||
/// @param s 待转换的utf8字符串
|
||||
/// @return Vec<u8> 转换结束后的Ascii字符串
|
||||
@ -125,6 +167,46 @@ impl PrintkWriter {
|
||||
ascii_str.push(b'\0');
|
||||
return ascii_str;
|
||||
}
|
||||
|
||||
fn __write_string_on_stack(&self, s: &str) {
|
||||
let s_len = s.len();
|
||||
assert!(s_len < 1024, "s_len is too long");
|
||||
let mut str_to_print: [u8; 1024] = [0; 1024];
|
||||
let mut i = 0;
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
0..=127 => {
|
||||
str_to_print[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
str_to_print[i] = b'\0';
|
||||
unsafe {
|
||||
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
fn __write_string_color_on_stack(&self, fr_color: u32, bk_color: u32, s: &str) {
|
||||
let s_len = s.len();
|
||||
assert!(s_len < 1024, "s_len is too long");
|
||||
let mut str_to_print: [u8; 1024] = [0; 1024];
|
||||
let mut i = 0;
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
0..=127 => {
|
||||
str_to_print[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
str_to_print[i] = b'\0';
|
||||
unsafe {
|
||||
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 为Printk Writer实现core::fmt::Write, 使得能够借助Rust自带的格式化组件,格式化字符并输出
|
||||
|
@ -7,7 +7,10 @@ use core::{
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use crate::syscall::SystemError;
|
||||
use crate::{
|
||||
process::preempt::{preempt_disable, preempt_enable},
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
///RwLock读写锁
|
||||
|
||||
@ -110,6 +113,15 @@ impl<T> RwLock<T> {
|
||||
#[inline]
|
||||
/// @brief 尝试获取READER守卫
|
||||
pub fn try_read(&self) -> Option<RwLockReadGuard<T>> {
|
||||
preempt_disable();
|
||||
let r = self.inner_try_read();
|
||||
if r.is_none() {
|
||||
preempt_enable();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
fn inner_try_read(&self) -> Option<RwLockReadGuard<T>> {
|
||||
let reader_value = self.current_reader();
|
||||
//得到自增后的reader_value, 包括了尝试获得READER守卫的进程
|
||||
let value;
|
||||
@ -165,6 +177,18 @@ impl<T> RwLock<T> {
|
||||
#[inline]
|
||||
/// @brief 尝试获得WRITER守卫
|
||||
pub fn try_write(&self) -> Option<RwLockWriteGuard<T>> {
|
||||
preempt_disable();
|
||||
let r = self.inner_try_write();
|
||||
if r.is_none() {
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
return r;
|
||||
} //当架构为arm时,有些代码需要作出调整compare_exchange=>compare_exchange_weak
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[allow(dead_code)]
|
||||
fn inner_try_write(&self) -> Option<RwLockWriteGuard<T>> {
|
||||
let res: bool = self
|
||||
.lock
|
||||
.compare_exchange(0, WRITER, Ordering::Acquire, Ordering::Relaxed)
|
||||
@ -178,7 +202,7 @@ impl<T> RwLock<T> {
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} //当架构为arm时,有些代码需要作出调整compare_exchange=>compare_exchange_weak
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
@ -196,8 +220,18 @@ impl<T> RwLock<T> {
|
||||
#[inline]
|
||||
/// @brief 尝试获得UPGRADER守卫
|
||||
pub fn try_upgradeable_read(&self) -> Option<RwLockUpgradableGuard<T>> {
|
||||
//获得UPGRADER守卫不需要查看读者位
|
||||
//如果获得读者锁失败,不需要撤回fetch_or的原子操作
|
||||
preempt_disable();
|
||||
let r = self.inner_try_upgradeable_read();
|
||||
if r.is_none() {
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
fn inner_try_upgradeable_read(&self) -> Option<RwLockUpgradableGuard<T>> {
|
||||
// 获得UPGRADER守卫不需要查看读者位
|
||||
// 如果获得读者锁失败,不需要撤回fetch_or的原子操作
|
||||
if self.lock.fetch_or(UPGRADED, Ordering::Acquire) & (WRITER | UPGRADED) == 0 {
|
||||
return Some(RwLockUpgradableGuard {
|
||||
inner: self,
|
||||
@ -318,7 +352,7 @@ impl<'rwlock, T> RwLockUpgradableGuard<'rwlock, T> {
|
||||
|
||||
let inner: &RwLock<T> = self.inner;
|
||||
|
||||
//自动移去UPGRADED比特位
|
||||
// 自动移去UPGRADED比特位
|
||||
mem::drop(self);
|
||||
|
||||
RwLockReadGuard {
|
||||
@ -422,6 +456,7 @@ impl<'rwlock, T> Drop for RwLockReadGuard<'rwlock, T> {
|
||||
fn drop(&mut self) {
|
||||
debug_assert!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED) > 0);
|
||||
self.lock.fetch_sub(READER, Ordering::Release);
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,6 +467,7 @@ impl<'rwlock, T> Drop for RwLockUpgradableGuard<'rwlock, T> {
|
||||
UPGRADED
|
||||
);
|
||||
self.inner.lock.fetch_sub(UPGRADED, Ordering::AcqRel);
|
||||
preempt_enable();
|
||||
//这里为啥要AcqRel? Release应该就行了?
|
||||
}
|
||||
}
|
||||
@ -442,5 +478,7 @@ impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
|
||||
self.inner
|
||||
.lock
|
||||
.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ use crate::syscall::SystemError;
|
||||
|
||||
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
#[inline]
|
||||
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
|
||||
*flags = local_irq_save() as u64;
|
||||
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut usize) {
|
||||
*flags = local_irq_save();
|
||||
unsafe {
|
||||
spin_lock(lock);
|
||||
}
|
||||
@ -22,12 +22,11 @@ pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
|
||||
|
||||
/// @brief 恢复rflags以及中断状态并解锁自旋锁
|
||||
#[inline]
|
||||
pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) {
|
||||
pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: usize) {
|
||||
unsafe {
|
||||
spin_unlock(lock);
|
||||
}
|
||||
// kdebug!("123");
|
||||
local_irq_restore(*flags as usize);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/// 判断一个自旋锁是否已经被加锁
|
||||
@ -129,27 +128,27 @@ impl RawSpinlock {
|
||||
}
|
||||
|
||||
/// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
pub fn lock_irqsave(&self, flags: &mut u64) {
|
||||
*flags = local_irq_save() as u64;
|
||||
pub fn lock_irqsave(&self, flags: &mut usize) {
|
||||
*flags = local_irq_save();
|
||||
self.lock();
|
||||
}
|
||||
|
||||
/// @brief 恢复rflags以及中断状态并解锁自旋锁
|
||||
pub fn unlock_irqrestore(&self, flags: &u64) {
|
||||
pub fn unlock_irqrestore(&self, flags: usize) {
|
||||
self.unlock();
|
||||
local_irq_restore(*flags as usize);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/// @brief 尝试保存中断状态到flags中,关闭中断,并对自旋锁加锁
|
||||
/// @return 加锁成功->true
|
||||
/// 加锁失败->false
|
||||
#[inline(always)]
|
||||
pub fn try_lock_irqsave(&self, flags: &mut u64) -> bool {
|
||||
*flags = local_irq_save() as u64;
|
||||
pub fn try_lock_irqsave(&self, flags: &mut usize) -> bool {
|
||||
*flags = local_irq_save();
|
||||
if self.try_lock() {
|
||||
return true;
|
||||
}
|
||||
local_irq_restore(*flags as usize);
|
||||
local_irq_restore(*flags);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -168,7 +167,7 @@ pub struct SpinLock<T> {
|
||||
#[derive(Debug)]
|
||||
pub struct SpinLockGuard<'a, T: 'a> {
|
||||
lock: &'a SpinLock<T>,
|
||||
flag: u64,
|
||||
flag: usize,
|
||||
}
|
||||
|
||||
/// 向编译器保证,SpinLock在线程之间是安全的.
|
||||
@ -194,7 +193,8 @@ impl<T> SpinLock<T> {
|
||||
}
|
||||
|
||||
pub fn lock_irqsave(&self) -> SpinLockGuard<T> {
|
||||
let mut flags: u64 = 0;
|
||||
let mut flags: usize = 0;
|
||||
|
||||
self.lock.lock_irqsave(&mut flags);
|
||||
// 加锁成功,返回一个守卫
|
||||
return SpinLockGuard {
|
||||
@ -214,7 +214,7 @@ impl<T> SpinLock<T> {
|
||||
}
|
||||
|
||||
pub fn try_lock_irqsave(&self) -> Result<SpinLockGuard<T>, SystemError> {
|
||||
let mut flags: u64 = 0;
|
||||
let mut flags: usize = 0;
|
||||
if self.lock.try_lock_irqsave(&mut flags) {
|
||||
return Ok(SpinLockGuard {
|
||||
lock: self,
|
||||
@ -245,7 +245,7 @@ impl<T> DerefMut for SpinLockGuard<'_, T> {
|
||||
impl<T> Drop for SpinLockGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
if self.flag != 0 {
|
||||
self.lock.lock.unlock_irqrestore(&self.flag);
|
||||
self.lock.lock.unlock_irqrestore(self.flag);
|
||||
} else {
|
||||
self.lock.lock.unlock();
|
||||
}
|
||||
|
Reference in New Issue
Block a user