mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-21 22:43:23 +00:00
feat(mm): 简单实现fat文件系统的文件映射 (#840)
- 添加文件映射相关接口,目前已简单实现fat文件系统的私有映射和共享映射 - 添加msync系统调用(由于当前未实现脏页自动回写,需要手动调用msync进行同步) - 简单实现PageCache(暂时使用HashMap进行文件页号与页的映射) - 添加新的PageFlags标志结构,原PageFlags改名为EntryFlags - 参考linux使用protection_map映射表进行页面标志的获取 - 添加页面回收机制 - 添加页面回收内核线程 - 缺页中断使用的锁修改为irq_save; 添加脏页回写机制 - 修复do_cow_page死锁问题 - 访问非法地址时发送信号终止进程 - 修复重复插入反向vma表的错误 - 添加test_filemap文件映射测试程序
This commit is contained in:
@ -12,9 +12,9 @@ use crate::{
|
||||
page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage, PhysPageFrame},
|
||||
},
|
||||
kernel_mapper::KernelMapper,
|
||||
page::{PageEntry, PageFlags, PAGE_1G_SHIFT},
|
||||
page::{EntryFlags, PageEntry, PAGE_1G_SHIFT},
|
||||
ucontext::UserMapper,
|
||||
MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
|
||||
MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags,
|
||||
},
|
||||
smp::cpu::ProcessorId,
|
||||
};
|
||||
@ -256,8 +256,74 @@ impl MemoryManagementArch for RiscV64MMArch {
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
const PAGE_NONE: usize = Self::ENTRY_FLAG_GLOBAL | Self::ENTRY_FLAG_READONLY;
|
||||
|
||||
const PAGE_READ: usize = PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY;
|
||||
|
||||
const PAGE_WRITE: usize =
|
||||
PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY | Self::ENTRY_FLAG_WRITEABLE;
|
||||
|
||||
const PAGE_EXEC: usize = PAGE_ENTRY_BASE | Self::ENTRY_FLAG_EXEC;
|
||||
|
||||
const PAGE_READ_EXEC: usize =
|
||||
PAGE_ENTRY_BASE | Self::ENTRY_FLAG_READONLY | Self::ENTRY_FLAG_EXEC;
|
||||
|
||||
const PAGE_WRITE_EXEC: usize = PAGE_ENTRY_BASE
|
||||
| Self::ENTRY_FLAG_READONLY
|
||||
| Self::ENTRY_FLAG_EXEC
|
||||
| Self::ENTRY_FLAG_WRITEABLE;
|
||||
|
||||
const PAGE_COPY: usize = Self::PAGE_READ;
|
||||
const PAGE_COPY_EXEC: usize = Self::PAGE_READ_EXEC;
|
||||
const PAGE_SHARED: usize = Self::PAGE_WRITE;
|
||||
const PAGE_SHARED_EXEC: usize = Self::PAGE_WRITE_EXEC;
|
||||
|
||||
const PAGE_COPY_NOEXEC: usize = 0;
|
||||
const PAGE_READONLY: usize = 0;
|
||||
const PAGE_READONLY_EXEC: usize = 0;
|
||||
|
||||
const PROTECTION_MAP: [EntryFlags<MMArch>; 16] = protection_map();
|
||||
}
|
||||
|
||||
const fn protection_map() -> [EntryFlags<MMArch>; 16] {
|
||||
let mut map = [0; 16];
|
||||
map[VmFlags::VM_NONE.bits()] = MMArch::PAGE_NONE;
|
||||
map[VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY;
|
||||
map[VmFlags::VM_WRITE.bits()] = MMArch::PAGE_COPY;
|
||||
map[VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_COPY;
|
||||
map[VmFlags::VM_EXEC.bits()] = MMArch::PAGE_READONLY_EXEC;
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY_EXEC;
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = MMArch::PAGE_COPY_EXEC;
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] =
|
||||
MMArch::PAGE_COPY_EXEC;
|
||||
map[VmFlags::VM_SHARED.bits()] = MMArch::PAGE_NONE;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_READ.bits()] = MMArch::PAGE_READONLY;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits()] = MMArch::PAGE_SHARED;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] =
|
||||
MMArch::PAGE_SHARED;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits()] = MMArch::PAGE_READONLY_EXEC;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] =
|
||||
MMArch::PAGE_READONLY_EXEC;
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] =
|
||||
MMArch::PAGE_SHARED_EXEC;
|
||||
map[VmFlags::VM_SHARED.bits()
|
||||
| VmFlags::VM_EXEC.bits()
|
||||
| VmFlags::VM_WRITE.bits()
|
||||
| VmFlags::VM_READ.bits()] = MMArch::PAGE_SHARED_EXEC;
|
||||
let mut ret = [unsafe { EntryFlags::from_data(0) }; 16];
|
||||
let mut index = 0;
|
||||
while index < 16 {
|
||||
ret[index] = unsafe { EntryFlags::from_data(map[index]) };
|
||||
index += 1;
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
const PAGE_ENTRY_BASE: usize = RiscV64MMArch::ENTRY_FLAG_PRESENT
|
||||
| RiscV64MMArch::ENTRY_FLAG_ACCESSED
|
||||
| RiscV64MMArch::ENTRY_FLAG_USER;
|
||||
|
||||
impl VirtAddr {
|
||||
/// 判断虚拟地址是否合法
|
||||
#[inline(always)]
|
||||
@ -270,8 +336,8 @@ impl VirtAddr {
|
||||
}
|
||||
|
||||
/// 获取内核地址默认的页面标志
|
||||
pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(_virt: VirtAddr) -> PageFlags<A> {
|
||||
PageFlags::from_data(RiscV64MMArch::ENTRY_FLAG_DEFAULT_PAGE)
|
||||
pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(_virt: VirtAddr) -> EntryFlags<A> {
|
||||
EntryFlags::from_data(RiscV64MMArch::ENTRY_FLAG_DEFAULT_PAGE)
|
||||
.set_user(false)
|
||||
.set_execute(true)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::arch::mm::LockedFrameAllocator;
|
||||
use crate::arch::mm::PageMapper;
|
||||
use crate::arch::MMArch;
|
||||
use crate::mm::page::PageFlags;
|
||||
use crate::mm::page::EntryFlags;
|
||||
use crate::mm::{PageTableKind, PhysAddr, VirtAddr};
|
||||
use crate::smp::core::smp_get_processor_id;
|
||||
use crate::smp::cpu::AtomicProcessorId;
|
||||
@ -92,7 +92,7 @@ impl EptMapper {
|
||||
&mut self,
|
||||
gpa: u64,
|
||||
hpa: u64,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
if self.readonly {
|
||||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
arch::kvm::vmx::ept::EptMapper,
|
||||
libs::mutex::Mutex,
|
||||
mm::{page::PageFlags, syscall::ProtFlags},
|
||||
mm::{page::EntryFlags, syscall::ProtFlags},
|
||||
virt::kvm::host_mem::{__gfn_to_pfn, kvm_vcpu_gfn_to_memslot, PAGE_MASK, PAGE_SHIFT},
|
||||
};
|
||||
use bitfield_struct::bitfield;
|
||||
@ -218,7 +218,7 @@ pub fn __direct_map(
|
||||
}
|
||||
// 把gpa映射到hpa
|
||||
let mut ept_mapper = EptMapper::lock();
|
||||
let page_flags = PageFlags::from_prot_flags(ProtFlags::from_bits_truncate(0x7_u64), false);
|
||||
let page_flags = EntryFlags::from_prot_flags(ProtFlags::from_bits_truncate(0x7_u64), false);
|
||||
unsafe {
|
||||
assert!(ept_mapper.walk(gpa, pfn << PAGE_SHIFT, page_flags).is_ok());
|
||||
}
|
||||
|
@ -10,15 +10,18 @@ use x86::{bits64::rflags::RFlags, controlregs::Cr4};
|
||||
use crate::{
|
||||
arch::{
|
||||
interrupt::{trap::X86PfErrorCode, TrapFrame},
|
||||
ipc::signal::{SigCode, Signal},
|
||||
mm::{MemoryManagementArch, X86_64MMArch},
|
||||
CurrentIrqArch, MMArch,
|
||||
},
|
||||
exception::InterruptArch,
|
||||
ipc::signal_types::{SigInfo, SigType},
|
||||
mm::{
|
||||
fault::{FaultFlags, PageFaultHandler, PageFaultMessage},
|
||||
ucontext::{AddressSpace, LockedVMA},
|
||||
VirtAddr, VmFaultReason, VmFlags,
|
||||
},
|
||||
process::ProcessManager,
|
||||
};
|
||||
|
||||
use super::LockedFrameAllocator;
|
||||
@ -28,7 +31,7 @@ pub type PageMapper =
|
||||
|
||||
impl X86_64MMArch {
|
||||
pub fn vma_access_error(vma: Arc<LockedVMA>, error_code: X86PfErrorCode) -> bool {
|
||||
let vm_flags = *vma.lock().vm_flags();
|
||||
let vm_flags = *vma.lock_irqsave().vm_flags();
|
||||
let foreign = false;
|
||||
if error_code.contains(X86PfErrorCode::X86_PF_PK) {
|
||||
return true;
|
||||
@ -223,20 +226,30 @@ impl X86_64MMArch {
|
||||
}
|
||||
|
||||
let current_address_space: Arc<AddressSpace> = AddressSpace::current().unwrap();
|
||||
let mut space_guard = current_address_space.write();
|
||||
let mut space_guard = current_address_space.write_irqsave();
|
||||
let mut fault;
|
||||
loop {
|
||||
let vma = space_guard.mappings.find_nearest(address);
|
||||
// let vma = space_guard.mappings.contains(address);
|
||||
|
||||
let vma = vma.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"can not find nearest vma, error_code: {:#b}, address: {:#x}",
|
||||
error_code,
|
||||
address.data(),
|
||||
)
|
||||
});
|
||||
let guard = vma.lock();
|
||||
let vma = match vma {
|
||||
Some(vma) => vma,
|
||||
None => {
|
||||
log::error!(
|
||||
"can not find nearest vma, error_code: {:#b}, address: {:#x}",
|
||||
error_code,
|
||||
address.data(),
|
||||
);
|
||||
let pid = ProcessManager::current_pid();
|
||||
let mut info =
|
||||
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
|
||||
Signal::SIGSEGV
|
||||
.send_signal_info(Some(&mut info), pid)
|
||||
.expect("failed to send SIGSEGV to process");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let guard = vma.lock_irqsave();
|
||||
let region = *guard.region();
|
||||
let vm_flags = *guard.vm_flags();
|
||||
drop(guard);
|
||||
@ -253,11 +266,18 @@ impl X86_64MMArch {
|
||||
)
|
||||
});
|
||||
} else {
|
||||
panic!(
|
||||
log::error!(
|
||||
"No mapped vma, error_code: {:#b}, address: {:#x}",
|
||||
error_code,
|
||||
address.data(),
|
||||
)
|
||||
);
|
||||
let pid = ProcessManager::current_pid();
|
||||
let mut info =
|
||||
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
|
||||
Signal::SIGSEGV
|
||||
.send_signal_info(Some(&mut info), pid)
|
||||
.expect("failed to send SIGSEGV to process");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,11 +289,9 @@ impl X86_64MMArch {
|
||||
);
|
||||
}
|
||||
let mapper = &mut space_guard.user_mapper.utable;
|
||||
let message = PageFaultMessage::new(vma.clone(), address, flags, mapper);
|
||||
|
||||
fault = PageFaultHandler::handle_mm_fault(
|
||||
PageFaultMessage::new(vma.clone(), address, flags),
|
||||
mapper,
|
||||
);
|
||||
fault = PageFaultHandler::handle_mm_fault(message);
|
||||
|
||||
if fault.contains(VmFaultReason::VM_FAULT_COMPLETED) {
|
||||
return;
|
||||
|
@ -28,8 +28,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::{PageEntry, PageFlags, PAGE_1G_SHIFT};
|
||||
use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr};
|
||||
use crate::mm::page::{EntryFlags, PageEntry, PAGE_1G_SHIFT};
|
||||
use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags};
|
||||
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -326,6 +326,93 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
}
|
||||
pkru::pkru_allows_pkey(pkru::vma_pkey(vma), write)
|
||||
}
|
||||
|
||||
const PROTECTION_MAP: [EntryFlags<MMArch>; 16] = protection_map();
|
||||
|
||||
const PAGE_NONE: usize =
|
||||
Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_ACCESSED | Self::ENTRY_FLAG_GLOBAL;
|
||||
|
||||
const PAGE_SHARED: usize = Self::ENTRY_FLAG_PRESENT
|
||||
| Self::ENTRY_FLAG_READWRITE
|
||||
| Self::ENTRY_FLAG_USER
|
||||
| Self::ENTRY_FLAG_ACCESSED
|
||||
| Self::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
const PAGE_SHARED_EXEC: usize = Self::ENTRY_FLAG_PRESENT
|
||||
| Self::ENTRY_FLAG_READWRITE
|
||||
| Self::ENTRY_FLAG_USER
|
||||
| Self::ENTRY_FLAG_ACCESSED;
|
||||
|
||||
const PAGE_COPY_NOEXEC: usize = Self::ENTRY_FLAG_PRESENT
|
||||
| Self::ENTRY_FLAG_USER
|
||||
| Self::ENTRY_FLAG_ACCESSED
|
||||
| Self::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
const PAGE_COPY_EXEC: usize =
|
||||
Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_USER | Self::ENTRY_FLAG_ACCESSED;
|
||||
|
||||
const PAGE_COPY: usize = Self::ENTRY_FLAG_PRESENT
|
||||
| Self::ENTRY_FLAG_USER
|
||||
| Self::ENTRY_FLAG_ACCESSED
|
||||
| Self::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
const PAGE_READONLY: usize = Self::ENTRY_FLAG_PRESENT
|
||||
| Self::ENTRY_FLAG_USER
|
||||
| Self::ENTRY_FLAG_ACCESSED
|
||||
| Self::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
const PAGE_READONLY_EXEC: usize =
|
||||
Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_USER | Self::ENTRY_FLAG_ACCESSED;
|
||||
|
||||
const PAGE_READ: usize = 0;
|
||||
const PAGE_READ_EXEC: usize = 0;
|
||||
const PAGE_WRITE: usize = 0;
|
||||
const PAGE_WRITE_EXEC: usize = 0;
|
||||
const PAGE_EXEC: usize = 0;
|
||||
}
|
||||
|
||||
/// 获取保护标志的映射表
|
||||
///
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `[usize; 16]`: 长度为16的映射表
|
||||
const fn protection_map() -> [EntryFlags<MMArch>; 16] {
|
||||
let mut map = [unsafe { EntryFlags::from_data(0) }; 16];
|
||||
unsafe {
|
||||
map[VmFlags::VM_NONE.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE);
|
||||
map[VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY);
|
||||
map[VmFlags::VM_WRITE.bits()] = EntryFlags::from_data(MMArch::PAGE_COPY);
|
||||
map[VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_COPY);
|
||||
map[VmFlags::VM_EXEC.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC);
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC);
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_COPY_EXEC);
|
||||
map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_COPY_EXEC);
|
||||
map[VmFlags::VM_SHARED.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_READONLY);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_SHARED);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_SHARED);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC);
|
||||
map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] =
|
||||
EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC);
|
||||
map[VmFlags::VM_SHARED.bits()
|
||||
| VmFlags::VM_EXEC.bits()
|
||||
| VmFlags::VM_WRITE.bits()
|
||||
| VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC);
|
||||
}
|
||||
// if X86_64MMArch::is_xd_reserved() {
|
||||
// map.iter_mut().for_each(|x| *x &= !Self::ENTRY_FLAG_NO_EXEC)
|
||||
// }
|
||||
map
|
||||
}
|
||||
|
||||
impl X86_64MMArch {
|
||||
@ -650,17 +737,17 @@ impl FrameAllocator for LockedFrameAllocator {
|
||||
}
|
||||
|
||||
/// 获取内核地址默认的页面标志
|
||||
pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> PageFlags<A> {
|
||||
pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> EntryFlags<A> {
|
||||
let info: X86_64MMBootstrapInfo = BOOTSTRAP_MM_INFO.unwrap();
|
||||
|
||||
if virt.data() >= info.kernel_code_start && virt.data() < info.kernel_code_end {
|
||||
// Remap kernel code execute
|
||||
return PageFlags::new().set_execute(true).set_write(true);
|
||||
return EntryFlags::new().set_execute(true).set_write(true);
|
||||
} else if virt.data() >= info.kernel_data_end && virt.data() < info.kernel_rodata_end {
|
||||
// Remap kernel rodata read only
|
||||
return PageFlags::new().set_execute(true);
|
||||
return EntryFlags::new().set_execute(true);
|
||||
} else {
|
||||
return PageFlags::new().set_write(true).set_execute(true);
|
||||
return EntryFlags::new().set_write(true).set_execute(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ const PKEY_MASK: usize = 1 << 32 | 1 << 33 | 1 << 34 | 1 << 35;
|
||||
/// ## 返回值
|
||||
/// - `u16`: vma的protection_key
|
||||
pub fn vma_pkey(vma: Arc<LockedVMA>) -> u16 {
|
||||
let guard = vma.lock();
|
||||
((guard.vm_flags().bits() & PKEY_MASK as u64) >> VM_PKEY_SHIFT) as u16
|
||||
let guard = vma.lock_irqsave();
|
||||
((guard.vm_flags().bits() & PKEY_MASK) >> VM_PKEY_SHIFT) as u16
|
||||
}
|
||||
|
||||
// TODO pkru实现参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/pkru.h
|
||||
|
Reference in New Issue
Block a user