mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +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:
parent
9fa0e95eee
commit
cf7f801e1d
@ -57,7 +57,8 @@ wait_queue_macros = { path = "crates/wait_queue_macros" }
|
||||
paste = "=1.0.14"
|
||||
slabmalloc = { path = "crates/rust-slabmalloc" }
|
||||
log = "0.4.21"
|
||||
|
||||
xarray = "0.1.0"
|
||||
lru = "0.12.3"
|
||||
|
||||
# target为x86_64时,使用下面的依赖
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
|
@ -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!(
|
||||
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 guard = vma.lock();
|
||||
);
|
||||
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
|
||||
|
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::{page_manager_lock_irqsave, PageFlags};
|
||||
use crate::mm::page::{page_manager_lock_irqsave, EntryFlags};
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
|
||||
@ -25,7 +25,7 @@ pub fn dma_alloc(pages: usize) -> (usize, NonNull<u8>) {
|
||||
// 清空这块区域,防止出现脏数据
|
||||
core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE);
|
||||
|
||||
let dma_flags: PageFlags<MMArch> = PageFlags::mmio_flags();
|
||||
let dma_flags: EntryFlags<MMArch> = EntryFlags::mmio_flags();
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let kernel_mapper = kernel_mapper.as_mut().unwrap();
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::PageFlags,
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::EntryFlags,
|
||||
MemoryManagementArch,
|
||||
},
|
||||
time::timer::{Timer, TimerFunction},
|
||||
@ -95,7 +95,7 @@ impl VideoRefreshManager {
|
||||
let count = PageFrameCount::new(
|
||||
page_align_up(frame_buffer_info_guard.buf_size()) / MMArch::PAGE_SIZE,
|
||||
);
|
||||
let page_flags: PageFlags<MMArch> = PageFlags::new().set_execute(true).set_write(true);
|
||||
let page_flags: EntryFlags<MMArch> = EntryFlags::new().set_execute(true).set_write(true);
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let mut kernel_mapper = kernel_mapper.as_mut();
|
||||
|
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::{page_manager_lock_irqsave, PageFlags};
|
||||
use crate::mm::page::{page_manager_lock_irqsave, EntryFlags};
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
|
||||
@ -32,7 +32,7 @@ unsafe impl Hal for HalImpl {
|
||||
// 清空这块区域,防止出现脏数据
|
||||
core::ptr::write_bytes(virt.data() as *mut u8, 0, count.data() * MMArch::PAGE_SIZE);
|
||||
|
||||
let dma_flags: PageFlags<MMArch> = PageFlags::mmio_flags();
|
||||
let dma_flags: EntryFlags<MMArch> = EntryFlags::mmio_flags();
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let kernel_mapper = kernel_mapper.as_mut().unwrap();
|
||||
|
@ -14,9 +14,12 @@ use alloc::{
|
||||
|
||||
use crate::driver::base::block::gendisk::GenDisk;
|
||||
use crate::driver::base::device::device_number::DeviceNumber;
|
||||
use crate::filesystem::vfs::file::PageCache;
|
||||
use crate::filesystem::vfs::utils::DName;
|
||||
use crate::filesystem::vfs::{Magic, SpecialNodeData, SuperBlock};
|
||||
use crate::ipc::pipe::LockedPipeInode;
|
||||
use crate::mm::fault::{PageFaultHandler, PageFaultMessage};
|
||||
use crate::mm::VmFaultReason;
|
||||
use crate::{
|
||||
driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
||||
filesystem::vfs::{
|
||||
@ -119,6 +122,9 @@ pub struct FATInode {
|
||||
|
||||
/// 目录名
|
||||
dname: DName,
|
||||
|
||||
/// 页缓存
|
||||
page_cache: Option<Arc<PageCache>>,
|
||||
}
|
||||
|
||||
impl FATInode {
|
||||
@ -216,8 +222,14 @@ impl LockedFATInode {
|
||||
},
|
||||
special_node: None,
|
||||
dname,
|
||||
page_cache: None,
|
||||
})));
|
||||
|
||||
if !inode.0.lock().inode_type.is_dir() {
|
||||
let page_cache = PageCache::new(Some(Arc::downgrade(&inode) as Weak<dyn IndexNode>));
|
||||
inode.0.lock().page_cache = Some(page_cache);
|
||||
}
|
||||
|
||||
inode.0.lock().self_ref = Arc::downgrade(&inode);
|
||||
|
||||
inode.0.lock().update_metadata();
|
||||
@ -272,6 +284,19 @@ impl FileSystem for FATFileSystem {
|
||||
FAT_MAX_NAMELEN,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn fault(&self, pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
PageFaultHandler::filemap_fault(pfm)
|
||||
}
|
||||
|
||||
unsafe fn map_pages(
|
||||
&self,
|
||||
pfm: &mut PageFaultMessage,
|
||||
start_pgoff: usize,
|
||||
end_pgoff: usize,
|
||||
) -> VmFaultReason {
|
||||
PageFaultHandler::filemap_map_pages(pfm, start_pgoff, end_pgoff)
|
||||
}
|
||||
}
|
||||
|
||||
impl FATFileSystem {
|
||||
@ -348,6 +373,7 @@ impl FATFileSystem {
|
||||
},
|
||||
special_node: None,
|
||||
dname: DName::default(),
|
||||
page_cache: None,
|
||||
})));
|
||||
|
||||
let result: Arc<FATFileSystem> = Arc::new(FATFileSystem {
|
||||
@ -1824,6 +1850,10 @@ impl IndexNode for LockedFATInode {
|
||||
.map(|item| item as Arc<dyn IndexNode>)
|
||||
.ok_or(SystemError::EINVAL)
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Arc<PageCache>> {
|
||||
self.0.lock().page_cache.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FATFsInfo {
|
||||
|
@ -7,10 +7,12 @@ use alloc::{
|
||||
};
|
||||
use log::error;
|
||||
use system_error::SystemError;
|
||||
use xarray::XArray;
|
||||
|
||||
use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData};
|
||||
use crate::filesystem::eventfd::EventFdInode;
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::{
|
||||
base::{block::SeekFrom, device::DevicePrivateData},
|
||||
tty::tty_device::TtyFilePrivateData,
|
||||
@ -18,6 +20,7 @@ use crate::{
|
||||
filesystem::procfs::ProcfsFilePrivateData,
|
||||
ipc::pipe::{LockedPipeInode, PipeFsPrivateData},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
mm::{page::Page, MemoryManagementArch},
|
||||
net::{
|
||||
event_poll::{EPollItem, EPollPrivateData, EventPoll},
|
||||
socket::SocketInode,
|
||||
@ -118,6 +121,66 @@ impl FileMode {
|
||||
return self.bits() & FileMode::O_ACCMODE.bits();
|
||||
}
|
||||
}
|
||||
|
||||
/// 页面缓存
|
||||
pub struct PageCache {
|
||||
xarray: SpinLock<XArray<Arc<Page>>>,
|
||||
inode: Option<Weak<dyn IndexNode>>,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for PageCache {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("PageCache")
|
||||
.field(
|
||||
"xarray",
|
||||
&self
|
||||
.xarray
|
||||
.lock()
|
||||
.range(0..((MMArch::PAGE_ADDRESS_SIZE >> MMArch::PAGE_SHIFT) as u64))
|
||||
.map(|(_, r)| (*r).clone())
|
||||
.collect::<Vec<Arc<Page>>>(),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PageCache {
|
||||
pub fn new(inode: Option<Weak<dyn IndexNode>>) -> Arc<PageCache> {
|
||||
let page_cache = Self {
|
||||
xarray: SpinLock::new(XArray::new()),
|
||||
inode,
|
||||
};
|
||||
Arc::new(page_cache)
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Option<Weak<dyn IndexNode>> {
|
||||
self.inode.clone()
|
||||
}
|
||||
|
||||
pub fn add_page(&self, offset: usize, page: &Arc<Page>) {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
cursor.store(page.clone());
|
||||
}
|
||||
|
||||
pub fn get_page(&self, offset: usize) -> Option<Arc<Page>> {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
let page = cursor.load().map(|r| (*r).clone());
|
||||
page
|
||||
}
|
||||
|
||||
pub fn remove_page(&self, offset: usize) {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
cursor.remove();
|
||||
}
|
||||
|
||||
pub fn set_inode(&mut self, inode: Weak<dyn IndexNode>) {
|
||||
self.inode = Some(inode)
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 抽象文件结构体
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
@ -683,7 +746,6 @@ impl FileDescriptorVec {
|
||||
// 把文件描述符数组对应位置设置为空
|
||||
let file = self.fds[fd as usize].take().unwrap();
|
||||
|
||||
assert!(Arc::strong_count(&file) == 1);
|
||||
return Ok(file);
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,16 @@ use crate::{
|
||||
casting::DowncastArc,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
mm::{fault::PageFaultMessage, VmFaultReason},
|
||||
time::PosixTimeSpec,
|
||||
};
|
||||
|
||||
use self::{core::generate_inode_id, file::FileMode, syscall::ModeType, utils::DName};
|
||||
use self::{
|
||||
core::generate_inode_id,
|
||||
file::{FileMode, PageCache},
|
||||
syscall::ModeType,
|
||||
utils::DName,
|
||||
};
|
||||
pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
|
||||
|
||||
/// vfs容许的最大的路径名称长度
|
||||
@ -556,6 +562,14 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
|
||||
fn parent(&self) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
return self.find("..");
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Arc<PageCache>> {
|
||||
log::error!(
|
||||
"function page_cache() has not yet been implemented for inode:{}",
|
||||
crate::libs::name::get_type_name(&self)
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl DowncastArc for dyn IndexNode {
|
||||
@ -805,6 +819,25 @@ pub trait FileSystem: Any + Sync + Send + Debug {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn super_block(&self) -> SuperBlock;
|
||||
|
||||
unsafe fn fault(&self, _pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
panic!(
|
||||
"fault() has not yet been implemented for filesystem: {}",
|
||||
crate::libs::name::get_type_name(&self)
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn map_pages(
|
||||
&self,
|
||||
_pfm: &mut PageFaultMessage,
|
||||
_start_pgoff: usize,
|
||||
_end_pgoff: usize,
|
||||
) -> VmFaultReason {
|
||||
panic!(
|
||||
"map_pages() has not yet been implemented for filesystem: {}",
|
||||
crate::libs::name::get_type_name(&self)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl DowncastArc for dyn FileSystem {
|
||||
|
@ -19,11 +19,14 @@ use crate::{
|
||||
rwlock::RwLock,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
mm::{fault::PageFaultMessage, VmFaultReason},
|
||||
};
|
||||
|
||||
use super::{
|
||||
file::FileMode, syscall::ModeType, utils::DName, FilePrivateData, FileSystem, FileType,
|
||||
IndexNode, InodeId, Magic, SuperBlock,
|
||||
file::{FileMode, PageCache},
|
||||
syscall::ModeType,
|
||||
utils::DName,
|
||||
FilePrivateData, FileSystem, FileType, IndexNode, InodeId, Magic, SuperBlock,
|
||||
};
|
||||
|
||||
const MOUNTFS_BLOCK_SIZE: u64 = 512;
|
||||
@ -501,6 +504,10 @@ impl IndexNode for MountFSInode {
|
||||
fn parent(&self) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
return self.do_parent().map(|inode| inode as Arc<dyn IndexNode>);
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Arc<PageCache>> {
|
||||
self.inner_inode.page_cache()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSystem for MountFS {
|
||||
@ -528,6 +535,19 @@ impl FileSystem for MountFS {
|
||||
fn super_block(&self) -> SuperBlock {
|
||||
SuperBlock::new(Magic::MOUNT_MAGIC, MOUNTFS_BLOCK_SIZE, MOUNTFS_MAX_NAMELEN)
|
||||
}
|
||||
|
||||
unsafe fn fault(&self, pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
self.inner_filesystem.fault(pfm)
|
||||
}
|
||||
|
||||
unsafe fn map_pages(
|
||||
&self,
|
||||
pfm: &mut PageFaultMessage,
|
||||
start_pgoff: usize,
|
||||
end_pgoff: usize,
|
||||
) -> VmFaultReason {
|
||||
self.inner_filesystem.map_pages(pfm, start_pgoff, end_pgoff)
|
||||
}
|
||||
}
|
||||
|
||||
/// MountList
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
syscall::user_access::{UserBufferReader, UserBufferWriter},
|
||||
time::PosixTimeSpec,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use ida::IdAllocator;
|
||||
@ -165,10 +165,10 @@ impl ShmManager {
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut cur_phys = PhysPageFrame::new(phys_page.0);
|
||||
for _ in 0..page_count.data() {
|
||||
let mut page = Page::new(true);
|
||||
page.set_shm_id(shm_id);
|
||||
let page = Arc::new(Page::new(true, cur_phys.phys_address()));
|
||||
page.write_irqsave().set_shm_id(shm_id);
|
||||
let paddr = cur_phys.phys_address();
|
||||
page_manager_guard.insert(paddr, page);
|
||||
page_manager_guard.insert(paddr, &page);
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
|
||||
@ -324,8 +324,8 @@ impl ShmManager {
|
||||
if map_count > 0 {
|
||||
// 设置共享内存物理页当映射计数等于0时可被回收
|
||||
for _ in 0..count.data() {
|
||||
let page = page_manager_guard.get_mut(&cur_phys.phys_address());
|
||||
page.set_dealloc_when_zero(true);
|
||||
let page = page_manager_guard.get_unwrap(&cur_phys.phys_address());
|
||||
page.write_irqsave().set_dealloc_when_zero(true);
|
||||
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
@ -436,7 +436,7 @@ impl KernelShm {
|
||||
|
||||
/// 共享内存段的映射计数(有多少个不同的VMA映射)
|
||||
pub fn map_count(&self) -> usize {
|
||||
let page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut id_set: HashSet<usize> = HashSet::new();
|
||||
let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr);
|
||||
let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap();
|
||||
@ -444,7 +444,8 @@ impl KernelShm {
|
||||
for _ in 0..page_count.data() {
|
||||
let page = page_manager_guard.get(&cur_phys.phys_address()).unwrap();
|
||||
id_set.extend(
|
||||
page.anon_vma()
|
||||
page.read_irqsave()
|
||||
.anon_vma()
|
||||
.iter()
|
||||
.map(|vma| vma.id())
|
||||
.collect::<Vec<_>>(),
|
||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||
libs::spinlock::SpinLock,
|
||||
mm::{
|
||||
allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame},
|
||||
page::{page_manager_lock_irqsave, PageFlags, PageFlushAll},
|
||||
page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll},
|
||||
syscall::ProtFlags,
|
||||
ucontext::{AddressSpace, VMA},
|
||||
VirtAddr, VmFlags,
|
||||
@ -324,8 +324,8 @@ impl Syscall {
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let vm_flags = VmFlags::from(shmflg);
|
||||
let destination = VirtPageFrame::new(region.start());
|
||||
let page_flags: PageFlags<MMArch> =
|
||||
PageFlags::from_prot_flags(ProtFlags::from(vm_flags), true);
|
||||
let page_flags: EntryFlags<MMArch> =
|
||||
EntryFlags::from_prot_flags(ProtFlags::from(vm_flags), true);
|
||||
let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
|
||||
|
||||
// 将共享内存映射到对应虚拟区域
|
||||
@ -351,14 +351,14 @@ impl Syscall {
|
||||
.mappings
|
||||
.contains(vaddr)
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
if vma.lock().region().start() != vaddr {
|
||||
if vma.lock_irqsave().region().start() != vaddr {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 验证用户虚拟内存区域是否有效
|
||||
let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?;
|
||||
|
||||
// 必须在取消映射前获取到PageFlags
|
||||
// 必须在取消映射前获取到EntryFlags
|
||||
let page_flags = address_write_guard
|
||||
.user_mapper
|
||||
.utable
|
||||
@ -386,7 +386,8 @@ impl Syscall {
|
||||
|
||||
// 将vma加入到对应Page的anon_vma
|
||||
page_manager_guard
|
||||
.get_mut(&phys.phys_address())
|
||||
.get_unwrap(&phys.phys_address())
|
||||
.write_irqsave()
|
||||
.insert_vma(vma.clone());
|
||||
|
||||
phys = phys.next();
|
||||
@ -394,7 +395,7 @@ impl Syscall {
|
||||
}
|
||||
|
||||
// 更新vma的映射状态
|
||||
vma.lock().set_mapped(true);
|
||||
vma.lock_irqsave().set_mapped(true);
|
||||
|
||||
vaddr.data()
|
||||
}
|
||||
@ -427,7 +428,7 @@ impl Syscall {
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
// 判断vaddr是否为起始地址
|
||||
if vma.lock().region().start() != vaddr {
|
||||
if vma.lock_irqsave().region().start() != vaddr {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
@ -440,9 +441,9 @@ impl Syscall {
|
||||
.0;
|
||||
|
||||
// 如果物理页的shm_id为None,代表不是共享页
|
||||
let page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?;
|
||||
let shm_id = page.shm_id().ok_or(SystemError::EINVAL)?;
|
||||
let shm_id = page.read_irqsave().shm_id().ok_or(SystemError::EINVAL)?;
|
||||
drop(page_manager_guard);
|
||||
|
||||
// 获取对应共享页管理信息
|
||||
|
@ -26,3 +26,4 @@ pub mod rand;
|
||||
pub mod wait_queue;
|
||||
|
||||
pub mod font;
|
||||
pub mod name;
|
||||
|
13
kernel/src/libs/name.rs
Normal file
13
kernel/src/libs/name.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use core::any::type_name;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_full_type_name<T>(_: &T) -> String {
|
||||
type_name::<T>().to_string()
|
||||
}
|
||||
|
||||
pub fn get_type_name<T>(_: &T) -> String {
|
||||
let full_name = type_name::<T>();
|
||||
full_name[(full_name.rfind("::").unwrap_or(0) + 2)..].to_string()
|
||||
}
|
@ -371,8 +371,9 @@ pub unsafe fn deallocate_page_frames(
|
||||
|
||||
if let Some(page) = page {
|
||||
// 如果page是共享页,将其共享页信息从SHM_MANAGER中删去
|
||||
if page.shared() {
|
||||
shm_manager_lock().free_id(&page.shm_id().unwrap());
|
||||
let page_guard = page.read_irqsave();
|
||||
if page_guard.shared() {
|
||||
shm_manager_lock().free_id(&page_guard.shm_id().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, mmio_buddy::mmio_pool,
|
||||
no_init::pseudo_map_phys, page::PageFlags, MemoryManagementArch, PhysAddr, VirtAddr,
|
||||
no_init::pseudo_map_phys, page::EntryFlags, MemoryManagementArch, PhysAddr, VirtAddr,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
@ -40,7 +40,7 @@ pub unsafe extern "C" fn rs_map_phys(vaddr: usize, paddr: usize, size: usize, fl
|
||||
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
|
||||
// debug!("rs_map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
|
||||
|
||||
let mut page_flags: PageFlags<MMArch> = PageFlags::new().set_execute(true).set_write(true);
|
||||
let mut page_flags: EntryFlags<MMArch> = EntryFlags::new().set_execute(true).set_write(true);
|
||||
if flags & PAGE_U_S as usize != 0 {
|
||||
page_flags = page_flags.set_user(true);
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
use core::{alloc::Layout, intrinsics::unlikely, panic};
|
||||
use core::{
|
||||
alloc::Layout,
|
||||
cmp::{max, min},
|
||||
intrinsics::unlikely,
|
||||
panic,
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
arch::{mm::PageMapper, MMArch},
|
||||
libs::align::align_down,
|
||||
mm::{
|
||||
page::{page_manager_lock_irqsave, PageFlags},
|
||||
page::{page_manager_lock_irqsave, EntryFlags},
|
||||
ucontext::LockedVMA,
|
||||
VirtAddr, VmFaultReason, VmFlags,
|
||||
},
|
||||
@ -14,6 +20,11 @@ use crate::{
|
||||
|
||||
use crate::mm::MemoryManagementArch;
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::FrameAllocator,
|
||||
page::{page_reclaimer_lock_irqsave, Page, PageFlags},
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
pub struct FaultFlags: u64{
|
||||
const FAULT_FLAG_WRITE = 1 << 0;
|
||||
@ -35,18 +46,42 @@ bitflags! {
|
||||
/// # 缺页异常信息结构体
|
||||
/// 包含了页面错误处理的相关信息,例如出错的地址、VMA等
|
||||
#[derive(Debug)]
|
||||
pub struct PageFaultMessage {
|
||||
pub struct PageFaultMessage<'a> {
|
||||
/// 产生缺页的VMA结构体
|
||||
vma: Arc<LockedVMA>,
|
||||
/// 缺页地址
|
||||
address: VirtAddr,
|
||||
/// 异常处理标志
|
||||
flags: FaultFlags,
|
||||
/// 页表映射器
|
||||
mapper: &'a mut PageMapper,
|
||||
/// 缺页的文件页在文件中的偏移量
|
||||
file_pgoff: Option<usize>,
|
||||
/// 缺页对应PageCache中的文件页
|
||||
page: Option<Arc<Page>>,
|
||||
/// 写时拷贝需要的页面
|
||||
cow_page: Option<Arc<Page>>,
|
||||
}
|
||||
|
||||
impl<'a> PageFaultMessage<'a> {
|
||||
pub fn new(
|
||||
vma: Arc<LockedVMA>,
|
||||
address: VirtAddr,
|
||||
flags: FaultFlags,
|
||||
}
|
||||
|
||||
impl PageFaultMessage {
|
||||
pub fn new(vma: Arc<LockedVMA>, address: VirtAddr, flags: FaultFlags) -> Self {
|
||||
mapper: &'a mut PageMapper,
|
||||
) -> Self {
|
||||
let guard = vma.lock_irqsave();
|
||||
let file_pgoff = guard.file_page_offset().map(|file_page_offset| {
|
||||
((address - guard.region().start()) >> MMArch::PAGE_SHIFT) + file_page_offset
|
||||
});
|
||||
Self {
|
||||
vma: vma.clone(),
|
||||
address,
|
||||
address: VirtAddr::new(crate::libs::align::page_align_down(address.data())),
|
||||
flags,
|
||||
file_pgoff,
|
||||
page: None,
|
||||
mapper,
|
||||
cow_page: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,16 +110,6 @@ impl PageFaultMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PageFaultMessage {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
vma: self.vma.clone(),
|
||||
address: self.address,
|
||||
flags: self.flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 缺页中断处理结构体
|
||||
pub struct PageFaultHandler;
|
||||
|
||||
@ -97,7 +122,7 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn handle_mm_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
pub unsafe fn handle_mm_fault(mut pfm: PageFaultMessage) -> VmFaultReason {
|
||||
let flags = pfm.flags();
|
||||
let vma = pfm.vma();
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
@ -113,13 +138,13 @@ impl PageFaultHandler {
|
||||
return VmFaultReason::VM_FAULT_SIGSEGV;
|
||||
}
|
||||
|
||||
let guard = vma.lock();
|
||||
let guard = vma.lock_irqsave();
|
||||
let vm_flags = *guard.vm_flags();
|
||||
drop(guard);
|
||||
if unlikely(vm_flags.contains(VmFlags::VM_HUGETLB)) {
|
||||
//TODO: 添加handle_hugetlb_fault处理大页缺页异常
|
||||
} else {
|
||||
Self::handle_normal_fault(pfm, mapper);
|
||||
Self::handle_normal_fault(&mut pfm);
|
||||
}
|
||||
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
@ -133,18 +158,16 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn handle_normal_fault(
|
||||
pfm: PageFaultMessage,
|
||||
mapper: &mut PageMapper,
|
||||
) -> VmFaultReason {
|
||||
pub unsafe fn handle_normal_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let address = pfm.address_aligned_down();
|
||||
let vma = pfm.vma.clone();
|
||||
let mapper = &mut pfm.mapper;
|
||||
if mapper.get_entry(address, 3).is_none() {
|
||||
mapper
|
||||
.allocate_table(address, 2)
|
||||
.expect("failed to allocate PUD table");
|
||||
}
|
||||
let page_flags = vma.lock().flags();
|
||||
let page_flags = vma.lock_irqsave().flags();
|
||||
|
||||
for level in 2..=3 {
|
||||
let level = MMArch::PAGE_LEVELS - level;
|
||||
@ -159,7 +182,7 @@ impl PageFaultHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Self::handle_pte_fault(pfm, mapper)
|
||||
Self::handle_pte_fault(pfm)
|
||||
}
|
||||
|
||||
/// 处理页表项异常
|
||||
@ -170,35 +193,37 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn handle_pte_fault(
|
||||
pfm: PageFaultMessage,
|
||||
mapper: &mut PageMapper,
|
||||
) -> VmFaultReason {
|
||||
pub unsafe fn handle_pte_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let address = pfm.address_aligned_down();
|
||||
let flags = pfm.flags;
|
||||
let vma = pfm.vma.clone();
|
||||
let mut ret = VmFaultReason::VM_FAULT_COMPLETED;
|
||||
let mapper = &pfm.mapper;
|
||||
|
||||
// pte存在
|
||||
if let Some(mut entry) = mapper.get_entry(address, 0) {
|
||||
if !entry.present() {
|
||||
ret = Self::do_swap_page(pfm.clone(), mapper);
|
||||
ret = Self::do_swap_page(pfm);
|
||||
}
|
||||
|
||||
if entry.protnone() && vma.is_accessible() {
|
||||
ret = Self::do_numa_page(pfm.clone(), mapper);
|
||||
ret = Self::do_numa_page(pfm);
|
||||
}
|
||||
|
||||
if flags.intersects(FaultFlags::FAULT_FLAG_WRITE | FaultFlags::FAULT_FLAG_UNSHARE) {
|
||||
if !entry.write() {
|
||||
ret = Self::do_wp_page(pfm.clone(), mapper);
|
||||
ret = Self::do_wp_page(pfm);
|
||||
} else {
|
||||
entry.set_flags(PageFlags::from_data(MMArch::ENTRY_FLAG_DIRTY));
|
||||
entry.set_flags(EntryFlags::from_data(MMArch::ENTRY_FLAG_DIRTY));
|
||||
}
|
||||
}
|
||||
} else if vma.is_anonymous() {
|
||||
ret = Self::do_anonymous_page(pfm.clone(), mapper);
|
||||
ret = Self::do_anonymous_page(pfm);
|
||||
} else {
|
||||
ret = Self::do_fault(pfm.clone(), mapper);
|
||||
ret = Self::do_fault(pfm);
|
||||
}
|
||||
|
||||
vma.lock().set_mapped(true);
|
||||
vma.lock_irqsave().set_mapped(true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -211,13 +236,12 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn do_anonymous_page(
|
||||
pfm: PageFaultMessage,
|
||||
mapper: &mut PageMapper,
|
||||
) -> VmFaultReason {
|
||||
pub unsafe fn do_anonymous_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let address = pfm.address_aligned_down();
|
||||
let vma = pfm.vma.clone();
|
||||
let guard = vma.lock();
|
||||
let guard = vma.lock_irqsave();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
if let Some(flush) = mapper.map(address, guard.flags()) {
|
||||
flush.flush();
|
||||
crate::debug::klog::mm::mm_debug_log(
|
||||
@ -229,9 +253,9 @@ impl PageFaultHandler {
|
||||
klog_types::LogSource::Buddy,
|
||||
);
|
||||
let paddr = mapper.translate(address).unwrap().0;
|
||||
let mut anon_vma_guard = page_manager_lock_irqsave();
|
||||
let page = anon_vma_guard.get_mut(&paddr);
|
||||
page.insert_vma(vma.clone());
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(vma.clone());
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
} else {
|
||||
VmFaultReason::VM_FAULT_OOM
|
||||
@ -246,16 +270,19 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn do_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_fault has not yet been implemented,
|
||||
fault message: {:?},
|
||||
pid: {}\n",
|
||||
pfm,
|
||||
crate::process::ProcessManager::current_pid().data()
|
||||
);
|
||||
// TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_fault
|
||||
pub unsafe fn do_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
if !pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE) {
|
||||
return Self::do_read_fault(pfm);
|
||||
} else if !pfm
|
||||
.vma()
|
||||
.lock_irqsave()
|
||||
.vm_flags()
|
||||
.contains(VmFlags::VM_SHARED)
|
||||
{
|
||||
return Self::do_cow_fault(pfm);
|
||||
} else {
|
||||
return Self::do_shared_fault(pfm);
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理私有文件映射的写时复制
|
||||
@ -266,16 +293,51 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub unsafe fn do_cow_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_cow_fault has not yet been implemented,
|
||||
fault message: {:?},
|
||||
pid: {}\n",
|
||||
pfm,
|
||||
crate::process::ProcessManager::current_pid().data()
|
||||
pub unsafe fn do_cow_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let mut ret = Self::filemap_fault(pfm);
|
||||
|
||||
if unlikely(ret.intersects(
|
||||
VmFaultReason::VM_FAULT_ERROR
|
||||
| VmFaultReason::VM_FAULT_NOPAGE
|
||||
| VmFaultReason::VM_FAULT_RETRY
|
||||
| VmFaultReason::VM_FAULT_DONE_COW,
|
||||
)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
let cache_page = pfm.page.clone().unwrap();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
let cow_page_phys = mapper.allocator_mut().allocate_one();
|
||||
if cow_page_phys.is_none() {
|
||||
return VmFaultReason::VM_FAULT_OOM;
|
||||
}
|
||||
let cow_page_phys = cow_page_phys.unwrap();
|
||||
|
||||
let cow_page = Arc::new(Page::new(false, cow_page_phys));
|
||||
pfm.cow_page = Some(cow_page.clone());
|
||||
|
||||
//复制PageCache内容到新的页内
|
||||
let new_frame = MMArch::phys_2_virt(cow_page_phys).unwrap();
|
||||
(new_frame.data() as *mut u8).copy_from_nonoverlapping(
|
||||
MMArch::phys_2_virt(cache_page.read_irqsave().phys_address())
|
||||
.unwrap()
|
||||
.data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
);
|
||||
// TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_cow_fault
|
||||
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
|
||||
// 新页加入页管理器中
|
||||
page_manager_guard.insert(cow_page_phys, &cow_page);
|
||||
cow_page.write_irqsave().set_page_cache_index(
|
||||
cache_page.read_irqsave().page_cache(),
|
||||
cache_page.read_irqsave().index(),
|
||||
);
|
||||
|
||||
ret = ret.union(Self::finish_fault(pfm));
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// 处理文件映射页的缺页异常
|
||||
@ -286,16 +348,19 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub unsafe fn do_read_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_read_fault has not yet been implemented,
|
||||
fault message: {:?},
|
||||
pid: {}\n",
|
||||
pfm,
|
||||
crate::process::ProcessManager::current_pid().data()
|
||||
);
|
||||
// TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_read_fault
|
||||
pub unsafe fn do_read_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs();
|
||||
|
||||
let mut ret = Self::do_fault_around(pfm);
|
||||
if !ret.is_empty() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fs.fault(pfm);
|
||||
|
||||
ret = ret.union(Self::finish_fault(pfm));
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// 处理对共享文件映射区写入引起的缺页
|
||||
@ -306,16 +371,16 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub unsafe fn do_shared_fault(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_shared_fault has not yet been implemented,
|
||||
fault message: {:?},
|
||||
pid: {}\n",
|
||||
pfm,
|
||||
crate::process::ProcessManager::current_pid().data()
|
||||
);
|
||||
// TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/memory.c#do_shared_fault
|
||||
pub unsafe fn do_shared_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let mut ret = Self::filemap_fault(pfm);
|
||||
|
||||
let cache_page = pfm.page.clone().expect("no cache_page in PageFaultMessage");
|
||||
|
||||
// 将pagecache页设为脏页,以便回收时能够回写
|
||||
cache_page.write_irqsave().add_flags(PageFlags::PG_DIRTY);
|
||||
ret = ret.union(Self::finish_fault(pfm));
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// 处理被置换页面的缺页异常
|
||||
@ -327,7 +392,7 @@ impl PageFaultHandler {
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn do_swap_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
pub unsafe fn do_swap_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_swap_page has not yet been implemented,
|
||||
fault message: {:?},
|
||||
@ -347,7 +412,7 @@ impl PageFaultHandler {
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn do_numa_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
pub unsafe fn do_numa_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
panic!(
|
||||
"do_numa_page has not yet been implemented,
|
||||
fault message: {:?},
|
||||
@ -366,17 +431,32 @@ impl PageFaultHandler {
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn do_wp_page(pfm: PageFaultMessage, mapper: &mut PageMapper) -> VmFaultReason {
|
||||
pub unsafe fn do_wp_page(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let address = pfm.address_aligned_down();
|
||||
let vma = pfm.vma.clone();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
let old_paddr = mapper.translate(address).unwrap().0;
|
||||
let mut page_manager = page_manager_lock_irqsave();
|
||||
let map_count = page_manager.get_mut(&old_paddr).map_count();
|
||||
let old_page = page_manager.get_unwrap(&old_paddr);
|
||||
let map_count = old_page.read_irqsave().map_count();
|
||||
drop(page_manager);
|
||||
|
||||
let mut entry = mapper.get_entry(address, 0).unwrap();
|
||||
let new_flags = entry.flags().set_write(true);
|
||||
let new_flags = entry.flags().set_write(true).set_dirty(true);
|
||||
|
||||
if vma.lock().vm_flags().contains(VmFlags::VM_SHARED) {
|
||||
// 共享映射,直接修改页表项保护位,标记为脏页
|
||||
let table = mapper.get_table(address, 0).unwrap();
|
||||
let i = table.index_of(address).unwrap();
|
||||
entry.set_flags(new_flags);
|
||||
table.set_entry(i, entry);
|
||||
|
||||
old_page.write_irqsave().add_flags(PageFlags::PG_DIRTY);
|
||||
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
} else if vma.is_anonymous() {
|
||||
// 私有匿名映射,根据引用计数判断是否拷贝页面
|
||||
if map_count == 1 {
|
||||
let table = mapper.get_table(address, 0).unwrap();
|
||||
let i = table.index_of(address).unwrap();
|
||||
@ -384,16 +464,39 @@ impl PageFaultHandler {
|
||||
table.set_entry(i, entry);
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
} else if let Some(flush) = mapper.map(address, new_flags) {
|
||||
let mut page_manager = page_manager_lock_irqsave();
|
||||
let old_page = page_manager.get_mut(&old_paddr);
|
||||
old_page.remove_vma(&vma);
|
||||
drop(page_manager);
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let old_page = page_manager_guard.get_unwrap(&old_paddr);
|
||||
old_page.write_irqsave().remove_vma(&vma);
|
||||
// drop(page_manager_guard);
|
||||
|
||||
flush.flush();
|
||||
let paddr = mapper.translate(address).unwrap().0;
|
||||
let mut anon_vma_guard = page_manager_lock_irqsave();
|
||||
let page = anon_vma_guard.get_mut(&paddr);
|
||||
page.insert_vma(vma.clone());
|
||||
// let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(vma.clone());
|
||||
|
||||
(MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
|
||||
MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
);
|
||||
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
} else {
|
||||
VmFaultReason::VM_FAULT_OOM
|
||||
}
|
||||
} else {
|
||||
// 私有文件映射,必须拷贝页面
|
||||
if let Some(flush) = mapper.map(address, new_flags) {
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let old_page = page_manager_guard.get_unwrap(&old_paddr);
|
||||
old_page.write_irqsave().remove_vma(&vma);
|
||||
// drop(page_manager_guard);
|
||||
|
||||
flush.flush();
|
||||
let paddr = mapper.translate(address).unwrap().0;
|
||||
// let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(vma.clone());
|
||||
|
||||
(MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8).copy_from_nonoverlapping(
|
||||
MMArch::phys_2_virt(old_paddr).unwrap().data() as *mut u8,
|
||||
@ -406,3 +509,211 @@ impl PageFaultHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 缺页附近页预读
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pfm`: 缺页异常信息
|
||||
/// - `mapper`: 页表映射器
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn do_fault_around(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let vma = pfm.vma();
|
||||
let address = pfm.address();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
if mapper.get_table(address, 0).is_none() {
|
||||
mapper
|
||||
.allocate_table(address, 0)
|
||||
.expect("failed to allocate pte table");
|
||||
}
|
||||
let vma_guard = vma.lock_irqsave();
|
||||
let vma_region = *vma_guard.region();
|
||||
drop(vma_guard);
|
||||
|
||||
// 缺页在VMA中的偏移量
|
||||
let vm_pgoff = (address - vma_region.start()) >> MMArch::PAGE_SHIFT;
|
||||
|
||||
// 缺页在PTE中的偏移量
|
||||
let pte_pgoff = (address.data() >> MMArch::PAGE_SHIFT) & (1 << MMArch::PAGE_ENTRY_SHIFT);
|
||||
|
||||
// 缺页在文件中的偏移量
|
||||
let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
|
||||
|
||||
let vma_pages_count = (vma_region.end() - vma_region.start()) >> MMArch::PAGE_SHIFT;
|
||||
|
||||
let fault_around_page_number = 16;
|
||||
|
||||
// 开始位置不能超出当前pte和vma头部
|
||||
let from_pte = max(
|
||||
align_down(pte_pgoff, fault_around_page_number),
|
||||
pte_pgoff - min(vm_pgoff, pte_pgoff),
|
||||
);
|
||||
|
||||
// pte结束位置不能超过:
|
||||
// 1.最大预读上限(默认16)
|
||||
// 2.最大pte(512)
|
||||
// 3.vma结束位置(pte_pgoff + (vma_pages_count - vm_pgoff)计算出vma结束页号对当前pte开头的偏移)
|
||||
let to_pte = min(
|
||||
from_pte + fault_around_page_number,
|
||||
min(
|
||||
1 << MMArch::PAGE_SHIFT,
|
||||
pte_pgoff + (vma_pages_count - vm_pgoff),
|
||||
),
|
||||
);
|
||||
|
||||
// 预先分配pte页表(如果不存在)
|
||||
if mapper.get_table(address, 0).is_none() && mapper.allocate_table(address, 0).is_none() {
|
||||
return VmFaultReason::VM_FAULT_OOM;
|
||||
}
|
||||
|
||||
let fs = pfm.vma().lock_irqsave().vm_file().unwrap().inode().fs();
|
||||
// from_pte - pte_pgoff得出预读起始pte相对缺失页的偏移,加上pfm.file_pgoff(缺失页在文件中的偏移)得出起始页在文件中的偏移,结束pte同理
|
||||
fs.map_pages(
|
||||
pfm,
|
||||
file_pgoff + (from_pte - pte_pgoff),
|
||||
file_pgoff + (to_pte - pte_pgoff),
|
||||
);
|
||||
|
||||
VmFaultReason::empty()
|
||||
}
|
||||
|
||||
/// 通用的VMA文件映射页面映射函数,将PageCache中的页面映射到进程空间
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pfm`: 缺页异常信息
|
||||
/// - `mapper`: 页表映射器
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn filemap_map_pages(
|
||||
pfm: &mut PageFaultMessage,
|
||||
|
||||
start_pgoff: usize,
|
||||
end_pgoff: usize,
|
||||
) -> VmFaultReason {
|
||||
let vma = pfm.vma();
|
||||
let vma_guard = vma.lock_irqsave();
|
||||
let file = vma_guard.vm_file().expect("no vm_file in vma");
|
||||
let page_cache = file.inode().page_cache().unwrap();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
// 起始页地址
|
||||
let addr = vma_guard.region().start
|
||||
+ ((start_pgoff
|
||||
- vma_guard
|
||||
.file_page_offset()
|
||||
.expect("file_page_offset is none"))
|
||||
<< MMArch::PAGE_SHIFT);
|
||||
|
||||
for pgoff in start_pgoff..=end_pgoff {
|
||||
if let Some(page) = page_cache.get_page(pgoff) {
|
||||
let page_guard = page.read_irqsave();
|
||||
if page_guard.flags().contains(PageFlags::PG_UPTODATE) {
|
||||
let phys = page_guard.phys_address();
|
||||
|
||||
let address =
|
||||
VirtAddr::new(addr.data() + ((pgoff - start_pgoff) << MMArch::PAGE_SHIFT));
|
||||
mapper
|
||||
.map_phys(address, phys, vma_guard.flags())
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
VmFaultReason::empty()
|
||||
}
|
||||
|
||||
/// 通用的VMA文件映射错误处理函数
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pfm`: 缺页异常信息
|
||||
/// - `mapper`: 页表映射器
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn filemap_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let vma = pfm.vma();
|
||||
let vma_guard = vma.lock_irqsave();
|
||||
let file = vma_guard.vm_file().expect("no vm_file in vma");
|
||||
let page_cache = file.inode().page_cache().unwrap();
|
||||
let file_pgoff = pfm.file_pgoff.expect("no file_pgoff");
|
||||
let mapper = &mut pfm.mapper;
|
||||
let mut ret = VmFaultReason::empty();
|
||||
|
||||
if let Some(page) = page_cache.get_page(file_pgoff) {
|
||||
// TODO 异步从磁盘中预读页面进PageCache
|
||||
|
||||
// 直接将PageCache中的页面作为要映射的页面
|
||||
pfm.page = Some(page.clone());
|
||||
} else {
|
||||
// TODO 同步预读
|
||||
//涉及磁盘IO,返回标志为VM_FAULT_MAJOR
|
||||
ret = VmFaultReason::VM_FAULT_MAJOR;
|
||||
// let mut buf: Vec<u8> = vec![0; MMArch::PAGE_SIZE];
|
||||
|
||||
let allocator = mapper.allocator_mut();
|
||||
|
||||
// 分配一个物理页面作为加入PageCache的新页
|
||||
let new_cache_page = allocator.allocate_one().unwrap();
|
||||
// (MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8)
|
||||
// .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE);
|
||||
file.pread(
|
||||
file_pgoff * MMArch::PAGE_SIZE,
|
||||
MMArch::PAGE_SIZE,
|
||||
core::slice::from_raw_parts_mut(
|
||||
MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
),
|
||||
)
|
||||
.expect("failed to read file to create pagecache page");
|
||||
|
||||
let page = Arc::new(Page::new(true, new_cache_page));
|
||||
pfm.page = Some(page.clone());
|
||||
|
||||
page.write_irqsave().add_flags(PageFlags::PG_LRU);
|
||||
page_manager_lock_irqsave().insert(new_cache_page, &page);
|
||||
page_reclaimer_lock_irqsave().insert_page(new_cache_page, &page);
|
||||
page_cache.add_page(file_pgoff, &page);
|
||||
|
||||
page.write_irqsave()
|
||||
.set_page_cache_index(Some(page_cache), Some(file_pgoff));
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
/// 将文件页映射到缺页地址
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pfm`: 缺页异常信息
|
||||
/// - `mapper`: 页表映射器
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub unsafe fn finish_fault(pfm: &mut PageFaultMessage) -> VmFaultReason {
|
||||
let vma = pfm.vma();
|
||||
let vma_guard = vma.lock_irqsave();
|
||||
let flags = pfm.flags();
|
||||
let cache_page = pfm.page.clone();
|
||||
let cow_page = pfm.cow_page.clone();
|
||||
let address = pfm.address();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
let page_to_map = if flags.contains(FaultFlags::FAULT_FLAG_WRITE)
|
||||
&& !vma_guard.vm_flags().contains(VmFlags::VM_SHARED)
|
||||
{
|
||||
// 私有文件映射的写时复制
|
||||
cow_page.expect("no cow_page in PageFaultMessage")
|
||||
} else {
|
||||
// 直接映射到PageCache
|
||||
cache_page.expect("no cache_page in PageFaultMessage")
|
||||
};
|
||||
|
||||
let page_phys = page_to_map.read_irqsave().phys_address();
|
||||
|
||||
mapper.map_phys(address, page_phys, vma_guard.flags());
|
||||
page_to_map.write_irqsave().insert_vma(pfm.vma());
|
||||
VmFaultReason::VM_FAULT_COMPLETED
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,11 @@ use crate::{
|
||||
filesystem::procfs::kmsg::kmsg_init,
|
||||
ipc::shm::shm_manager_init,
|
||||
libs::printk::PrintkWriter,
|
||||
mm::{allocator::slab::slab_init, mmio_buddy::mmio_init, page::page_manager_init},
|
||||
mm::{
|
||||
allocator::slab::slab_init,
|
||||
mmio_buddy::mmio_init,
|
||||
page::{page_manager_init, page_reclaimer_init},
|
||||
},
|
||||
};
|
||||
|
||||
use super::MemoryManagementArch;
|
||||
@ -57,6 +61,8 @@ pub unsafe fn mm_init() {
|
||||
page_manager_init();
|
||||
// enable SHM_MANAGER
|
||||
shm_manager_init();
|
||||
// enable PAGE_RECLAIMER
|
||||
page_reclaimer_init();
|
||||
|
||||
MM_INIT
|
||||
.compare_exchange(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::{page::PageFlags, PageTableKind, PhysAddr, VirtAddr};
|
||||
use super::{page::EntryFlags, PageTableKind, PhysAddr, VirtAddr};
|
||||
use crate::{
|
||||
arch::{
|
||||
mm::{LockedFrameAllocator, PageMapper},
|
||||
@ -104,7 +104,7 @@ impl KernelMapper {
|
||||
mut vaddr: VirtAddr,
|
||||
mut paddr: PhysAddr,
|
||||
size: usize,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
flush: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
if self.readonly {
|
||||
|
@ -12,7 +12,7 @@ impl LockedVMA {
|
||||
_flusher: impl Flusher<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
//TODO https://code.dragonos.org.cn/xref/linux-6.6.21/mm/madvise.c?fi=madvise#do_madvise
|
||||
let mut vma = self.lock();
|
||||
let mut vma = self.lock_irqsave();
|
||||
let mut new_flags = *vma.vm_flags();
|
||||
match behavior {
|
||||
MadvFlags::MADV_REMOVE => {
|
||||
|
@ -12,7 +12,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use log::{debug, error, info, warn};
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::page::{PageFlags, PAGE_4K_SIZE};
|
||||
use super::page::{EntryFlags, PAGE_4K_SIZE};
|
||||
use super::{PhysAddr, VirtAddr};
|
||||
|
||||
// 最大的伙伴块的幂
|
||||
@ -552,7 +552,7 @@ impl MmioBuddyMemPool {
|
||||
unsafe {
|
||||
let x: Option<(
|
||||
PhysAddr,
|
||||
PageFlags<MMArch>,
|
||||
EntryFlags<MMArch>,
|
||||
crate::mm::page::PageFlush<MMArch>,
|
||||
)> = kernel_mapper
|
||||
.as_mut()
|
||||
@ -677,7 +677,7 @@ impl MMIOSpaceGuard {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let flags = PageFlags::mmio_flags();
|
||||
let flags = EntryFlags::mmio_flags();
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::sync::Arc;
|
||||
use page::EntryFlags;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::MMArch;
|
||||
@ -40,7 +41,7 @@ static mut __IDLE_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = None;
|
||||
bitflags! {
|
||||
/// Virtual memory flags
|
||||
#[allow(clippy::bad_bit_mask)]
|
||||
pub struct VmFlags:u64{
|
||||
pub struct VmFlags:usize{
|
||||
const VM_NONE = 0x00000000;
|
||||
|
||||
const VM_READ = 0x00000001;
|
||||
@ -93,6 +94,27 @@ bitflags! {
|
||||
const VM_FAULT_NEEDDSYNC = 0x002000;
|
||||
const VM_FAULT_COMPLETED = 0x004000;
|
||||
const VM_FAULT_HINDEX_MASK = 0x0f0000;
|
||||
const VM_FAULT_ERROR = 0x000001 | 0x000002 | 0x000040 | 0x000010 | 0x000020 | 0x000800;
|
||||
}
|
||||
|
||||
pub struct MsFlags:usize {
|
||||
const MS_ASYNC = 1;
|
||||
const MS_INVALIDATE = 2;
|
||||
const MS_SYNC = 4;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Index<VmFlags> for [usize] {
|
||||
type Output = usize;
|
||||
|
||||
fn index(&self, index: VmFlags) -> &Self::Output {
|
||||
&self[index.bits]
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::IndexMut<VmFlags> for [usize] {
|
||||
fn index_mut(&mut self, index: VmFlags) -> &mut Self::Output {
|
||||
&mut self[index.bits]
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,7 +621,7 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
|
||||
|
||||
/// 创建页表项
|
||||
///
|
||||
/// 这是一个低阶api,用于根据物理地址以及指定好的pageflags,创建页表项
|
||||
/// 这是一个低阶api,用于根据物理地址以及指定好的EntryFlags,创建页表项
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
@ -631,6 +653,48 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
const PAGE_NONE: usize;
|
||||
const PAGE_SHARED: usize;
|
||||
const PAGE_SHARED_EXEC: usize;
|
||||
const PAGE_COPY_NOEXEC: usize;
|
||||
const PAGE_COPY_EXEC: usize;
|
||||
const PAGE_COPY: usize;
|
||||
const PAGE_READONLY: usize;
|
||||
const PAGE_READONLY_EXEC: usize;
|
||||
|
||||
const PAGE_READ: usize;
|
||||
const PAGE_READ_EXEC: usize;
|
||||
const PAGE_WRITE: usize;
|
||||
const PAGE_WRITE_EXEC: usize;
|
||||
const PAGE_EXEC: usize;
|
||||
|
||||
const PROTECTION_MAP: [EntryFlags<Self>; 16];
|
||||
|
||||
/// 页面保护标志转换函数
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `vm_flags`: VmFlags标志
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - EntryFlags: 页面的保护位
|
||||
fn vm_get_page_prot(vm_flags: VmFlags) -> EntryFlags<Self> {
|
||||
let map = Self::PROTECTION_MAP;
|
||||
let mut ret = map[vm_flags
|
||||
.intersection(
|
||||
VmFlags::VM_READ | VmFlags::VM_WRITE | VmFlags::VM_EXEC | VmFlags::VM_SHARED,
|
||||
)
|
||||
.bits()];
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
// 如果xd位被保留,那么将可执行性设置为true
|
||||
if crate::arch::mm::X86_64MMArch::is_xd_reserved() {
|
||||
ret = ret.set_execute(true);
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 虚拟地址范围
|
||||
|
@ -19,7 +19,7 @@ use core::marker::PhantomData;
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage},
|
||||
page::PageFlags,
|
||||
page::EntryFlags,
|
||||
PageTableKind, VirtAddr,
|
||||
};
|
||||
|
||||
@ -141,7 +141,7 @@ impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
|
||||
/// 并且,内核引导文件必须以4K页为粒度,填写了前100M的内存映射关系。(具体以本文件开头的注释为准)
|
||||
#[inline(never)]
|
||||
pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
|
||||
let flags: PageFlags<MMArch> = PageFlags::new().set_write(true);
|
||||
let flags: EntryFlags<MMArch> = EntryFlags::new().set_write(true);
|
||||
|
||||
pseudo_map_phys_with_flags(vaddr, paddr, count, flags);
|
||||
}
|
||||
@ -150,7 +150,7 @@ pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrame
|
||||
/// with READ_ONLY and EXECUTE flags.
|
||||
#[inline(never)]
|
||||
pub unsafe fn pseudo_map_phys_ro(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
|
||||
let flags: PageFlags<MMArch> = PageFlags::new().set_write(false).set_execute(true);
|
||||
let flags: EntryFlags<MMArch> = EntryFlags::new().set_write(false).set_execute(true);
|
||||
|
||||
pseudo_map_phys_with_flags(vaddr, paddr, count, flags);
|
||||
}
|
||||
@ -160,7 +160,7 @@ pub unsafe fn pseudo_map_phys_with_flags(
|
||||
vaddr: VirtAddr,
|
||||
paddr: PhysAddr,
|
||||
count: PageFrameCount,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
) {
|
||||
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
|
||||
assert!(paddr.check_aligned(MMArch::PAGE_SIZE));
|
||||
|
@ -1,3 +1,4 @@
|
||||
use alloc::string::ToString;
|
||||
use core::{
|
||||
fmt::{self, Debug, Error, Formatter},
|
||||
marker::PhantomData,
|
||||
@ -5,16 +6,26 @@ use core::{
|
||||
ops::Add,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use log::{error, info};
|
||||
use lru::LruCache;
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::ipi::send_ipi, MMArch},
|
||||
arch::{interrupt::ipi::send_ipi, mm::LockedFrameAllocator, MMArch},
|
||||
exception::ipi::{IpiKind, IpiTarget},
|
||||
filesystem::vfs::{file::PageCache, FilePrivateData},
|
||||
init::initcall::INITCALL_CORE,
|
||||
ipc::shm::ShmId,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
libs::{
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
process::{ProcessControlBlock, ProcessManager},
|
||||
time::{sleep::usleep, PosixTimeSpec},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -53,7 +64,7 @@ pub fn page_manager_lock_irqsave() -> SpinLockGuard<'static, PageManager> {
|
||||
|
||||
// 物理页管理器
|
||||
pub struct PageManager {
|
||||
phys2page: HashMap<PhysAddr, Page>,
|
||||
phys2page: HashMap<PhysAddr, Arc<Page>>,
|
||||
}
|
||||
|
||||
impl PageManager {
|
||||
@ -67,18 +78,21 @@ impl PageManager {
|
||||
self.phys2page.contains_key(paddr)
|
||||
}
|
||||
|
||||
pub fn get(&self, paddr: &PhysAddr) -> Option<&Page> {
|
||||
self.phys2page.get(paddr)
|
||||
pub fn get(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
|
||||
page_reclaimer_lock_irqsave().get(paddr);
|
||||
self.phys2page.get(paddr).cloned()
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, paddr: &PhysAddr) -> &mut Page {
|
||||
pub fn get_unwrap(&mut self, paddr: &PhysAddr) -> Arc<Page> {
|
||||
page_reclaimer_lock_irqsave().get(paddr);
|
||||
self.phys2page
|
||||
.get_mut(paddr)
|
||||
.unwrap_or_else(|| panic!("{:?}", paddr))
|
||||
.get(paddr)
|
||||
.unwrap_or_else(|| panic!("Phys Page not found, {:?}", paddr))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, paddr: PhysAddr, page: Page) {
|
||||
self.phys2page.insert(paddr, page);
|
||||
pub fn insert(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
|
||||
self.phys2page.insert(paddr, page.clone());
|
||||
}
|
||||
|
||||
pub fn remove_page(&mut self, paddr: &PhysAddr) {
|
||||
@ -86,8 +100,236 @@ impl PageManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// 物理页面信息
|
||||
pub static mut PAGE_RECLAIMER: Option<SpinLock<PageReclaimer>> = None;
|
||||
|
||||
pub fn page_reclaimer_init() {
|
||||
info!("page_reclaimer_init");
|
||||
let page_reclaimer = SpinLock::new(PageReclaimer::new());
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
unsafe { PAGE_RECLAIMER = Some(page_reclaimer) };
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
info!("page_reclaimer_init done");
|
||||
}
|
||||
|
||||
/// 页面回收线程
|
||||
static mut PAGE_RECLAIMER_THREAD: Option<Arc<ProcessControlBlock>> = None;
|
||||
|
||||
/// 页面回收线程初始化函数
|
||||
#[unified_init(INITCALL_CORE)]
|
||||
fn page_reclaimer_thread_init() -> Result<(), SystemError> {
|
||||
let closure = crate::process::kthread::KernelThreadClosure::StaticEmptyClosure((
|
||||
&(page_reclaim_thread as fn() -> i32),
|
||||
(),
|
||||
));
|
||||
let pcb = crate::process::kthread::KernelThreadMechanism::create_and_run(
|
||||
closure,
|
||||
"page_reclaim".to_string(),
|
||||
)
|
||||
.ok_or("")
|
||||
.expect("create tty_refresh thread failed");
|
||||
unsafe {
|
||||
PAGE_RECLAIMER_THREAD = Some(pcb);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 页面回收线程执行的函数
|
||||
fn page_reclaim_thread() -> i32 {
|
||||
loop {
|
||||
let usage = unsafe { LockedFrameAllocator.usage() };
|
||||
// log::info!("usage{:?}", usage);
|
||||
|
||||
// 保留4096个页面,总计16MB的空闲空间
|
||||
if usage.free().data() < 4096 {
|
||||
let page_to_free = 4096;
|
||||
page_reclaimer_lock_irqsave().shrink_list(PageFrameCount::new(page_to_free));
|
||||
} else {
|
||||
//TODO 暂时让页面回收线程负责脏页回写任务,后续需要分离
|
||||
page_reclaimer_lock_irqsave().flush_dirty_pages();
|
||||
// 休眠5秒
|
||||
// log::info!("sleep");
|
||||
let _ = usleep(PosixTimeSpec::new(5, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取页面回收器
|
||||
pub fn page_reclaimer_lock_irqsave() -> SpinLockGuard<'static, PageReclaimer> {
|
||||
unsafe { PAGE_RECLAIMER.as_ref().unwrap().lock_irqsave() }
|
||||
}
|
||||
|
||||
/// 页面回收器
|
||||
pub struct PageReclaimer {
|
||||
lru: LruCache<PhysAddr, Arc<Page>>,
|
||||
}
|
||||
|
||||
impl PageReclaimer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
lru: LruCache::unbounded(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
|
||||
self.lru.get(paddr).cloned()
|
||||
}
|
||||
|
||||
pub fn insert_page(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
|
||||
self.lru.put(paddr, page.clone());
|
||||
}
|
||||
|
||||
/// lru链表缩减
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `count`: 需要缩减的页面数量
|
||||
pub fn shrink_list(&mut self, count: PageFrameCount) {
|
||||
for _ in 0..count.data() {
|
||||
let (paddr, page) = self.lru.pop_lru().expect("pagecache is empty");
|
||||
let page_cache = page.read_irqsave().page_cache().unwrap();
|
||||
for vma in page.read_irqsave().anon_vma() {
|
||||
let address_space = vma.lock_irqsave().address_space().unwrap();
|
||||
let address_space = address_space.upgrade().unwrap();
|
||||
let mut guard = address_space.write();
|
||||
let mapper = &mut guard.user_mapper.utable;
|
||||
let virt = vma.lock_irqsave().page_address(&page).unwrap();
|
||||
unsafe {
|
||||
mapper.unmap(virt, false).unwrap().flush();
|
||||
}
|
||||
}
|
||||
page_cache.remove_page(page.read_irqsave().index().unwrap());
|
||||
page_manager_lock_irqsave().remove_page(&paddr);
|
||||
if page.read_irqsave().flags.contains(PageFlags::PG_DIRTY) {
|
||||
Self::page_writeback(&page, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 唤醒页面回收线程
|
||||
pub fn wakeup_claim_thread() {
|
||||
// log::info!("wakeup_claim_thread");
|
||||
let _ = ProcessManager::wakeup(unsafe { PAGE_RECLAIMER_THREAD.as_ref().unwrap() });
|
||||
}
|
||||
|
||||
/// 脏页回写函数
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `page`: 需要回写的脏页
|
||||
/// - `unmap`: 是否取消映射
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub fn page_writeback(page: &Arc<Page>, unmap: bool) {
|
||||
if !unmap {
|
||||
page.write_irqsave().remove_flags(PageFlags::PG_DIRTY);
|
||||
}
|
||||
|
||||
for vma in page.read_irqsave().anon_vma() {
|
||||
let address_space = vma.lock_irqsave().address_space().unwrap();
|
||||
let address_space = address_space.upgrade().unwrap();
|
||||
let mut guard = address_space.write();
|
||||
let mapper = &mut guard.user_mapper.utable;
|
||||
let virt = vma.lock_irqsave().page_address(page).unwrap();
|
||||
if unmap {
|
||||
unsafe {
|
||||
mapper.unmap(virt, false).unwrap().flush();
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
// 保护位设为只读
|
||||
mapper.remap(
|
||||
virt,
|
||||
mapper.get_entry(virt, 0).unwrap().flags().set_write(false),
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
let inode = page
|
||||
.read_irqsave()
|
||||
.page_cache
|
||||
.clone()
|
||||
.unwrap()
|
||||
.inode()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.upgrade()
|
||||
.unwrap();
|
||||
inode
|
||||
.write_at(
|
||||
page.read_irqsave().index().unwrap(),
|
||||
MMArch::PAGE_SIZE,
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
MMArch::phys_2_virt(page.read_irqsave().phys_addr)
|
||||
.unwrap()
|
||||
.data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
)
|
||||
},
|
||||
SpinLock::new(FilePrivateData::Unused).lock(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// lru脏页刷新
|
||||
pub fn flush_dirty_pages(&self) {
|
||||
// log::info!("flush_dirty_pages");
|
||||
let iter = self.lru.iter();
|
||||
for (_, page) in iter {
|
||||
if page.read_irqsave().flags().contains(PageFlags::PG_DIRTY) {
|
||||
Self::page_writeback(page, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct PageFlags: u64 {
|
||||
const PG_LOCKED = 1 << 0;
|
||||
const PG_WRITEBACK = 1 << 1;
|
||||
const PG_REFERENCED = 1 << 2;
|
||||
const PG_UPTODATE = 1 << 3;
|
||||
const PG_DIRTY = 1 << 4;
|
||||
const PG_LRU = 1 << 5;
|
||||
const PG_HEAD = 1 << 6;
|
||||
const PG_WAITERS = 1 << 7;
|
||||
const PG_ACTIVE = 1 << 8;
|
||||
const PG_WORKINGSET = 1 << 9;
|
||||
const PG_ERROR = 1 << 10;
|
||||
const PG_SLAB = 1 << 11;
|
||||
const PG_RESERVED = 1 << 14;
|
||||
const PG_PRIVATE = 1 << 15;
|
||||
const PG_RECLAIM = 1 << 18;
|
||||
const PG_SWAPBACKED = 1 << 19;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Page {
|
||||
inner: RwLock<InnerPage>,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
|
||||
let inner = InnerPage::new(shared, phys_addr);
|
||||
Self {
|
||||
inner: RwLock::new(inner),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_irqsave(&self) -> RwLockReadGuard<InnerPage> {
|
||||
self.inner.read_irqsave()
|
||||
}
|
||||
|
||||
pub fn write_irqsave(&self) -> RwLockWriteGuard<InnerPage> {
|
||||
self.inner.write_irqsave()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// 物理页面信息
|
||||
pub struct InnerPage {
|
||||
/// 映射计数
|
||||
map_count: usize,
|
||||
/// 是否为共享页
|
||||
@ -98,10 +340,17 @@ pub struct Page {
|
||||
shm_id: Option<ShmId>,
|
||||
/// 映射到当前page的VMA
|
||||
anon_vma: HashSet<Arc<LockedVMA>>,
|
||||
/// 标志
|
||||
flags: PageFlags,
|
||||
/// 页所在的物理页帧号
|
||||
phys_addr: PhysAddr,
|
||||
/// 在pagecache中的偏移
|
||||
index: Option<usize>,
|
||||
page_cache: Option<Arc<PageCache>>,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn new(shared: bool) -> Self {
|
||||
impl InnerPage {
|
||||
pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
|
||||
let dealloc_when_zero = !shared;
|
||||
Self {
|
||||
map_count: 0,
|
||||
@ -109,6 +358,10 @@ impl Page {
|
||||
free_when_zero: dealloc_when_zero,
|
||||
shm_id: None,
|
||||
anon_vma: HashSet::new(),
|
||||
flags: PageFlags::empty(),
|
||||
phys_addr,
|
||||
index: None,
|
||||
page_cache: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +390,31 @@ impl Page {
|
||||
self.shm_id
|
||||
}
|
||||
|
||||
pub fn index(&self) -> Option<usize> {
|
||||
self.index
|
||||
}
|
||||
|
||||
pub fn page_cache(&self) -> Option<Arc<PageCache>> {
|
||||
self.page_cache.clone()
|
||||
}
|
||||
|
||||
pub fn set_page_cache(&mut self, page_cache: Option<Arc<PageCache>>) {
|
||||
self.page_cache = page_cache;
|
||||
}
|
||||
|
||||
pub fn set_index(&mut self, index: Option<usize>) {
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
pub fn set_page_cache_index(
|
||||
&mut self,
|
||||
page_cache: Option<Arc<PageCache>>,
|
||||
index: Option<usize>,
|
||||
) {
|
||||
self.page_cache = page_cache;
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
pub fn set_shm_id(&mut self, shm_id: ShmId) {
|
||||
self.shm_id = Some(shm_id);
|
||||
}
|
||||
@ -154,6 +432,31 @@ impl Page {
|
||||
pub fn map_count(&self) -> usize {
|
||||
self.map_count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flags(&self) -> &PageFlags {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_flags(&mut self, flags: PageFlags) {
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_flags(&mut self, flags: PageFlags) {
|
||||
self.flags = self.flags.union(flags);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn remove_flags(&mut self, flags: PageFlags) {
|
||||
self.flags = self.flags.difference(flags);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn phys_address(&self) -> PhysAddr {
|
||||
self.phys_addr
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -329,8 +632,19 @@ impl<Arch: MemoryManagementArch> PageTable<Arch> {
|
||||
new_table.set_entry(i, entry);
|
||||
} else {
|
||||
let phys = allocator.allocate_one()?;
|
||||
let mut anon_vma_guard = page_manager_lock_irqsave();
|
||||
anon_vma_guard.insert(phys, Page::new(false));
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let old_phys = entry.address().unwrap();
|
||||
let old_page = page_manager_guard.get_unwrap(&old_phys);
|
||||
let new_page =
|
||||
Arc::new(Page::new(old_page.read_irqsave().shared(), phys));
|
||||
if let Some(ref page_cache) = old_page.read_irqsave().page_cache() {
|
||||
new_page.write_irqsave().set_page_cache_index(
|
||||
Some(page_cache.clone()),
|
||||
old_page.read_irqsave().index(),
|
||||
);
|
||||
}
|
||||
|
||||
page_manager_guard.insert(phys, &new_page);
|
||||
let old_phys = entry.address().unwrap();
|
||||
let frame = MMArch::phys_2_virt(phys).unwrap().data() as *mut u8;
|
||||
frame.copy_from_nonoverlapping(
|
||||
@ -372,7 +686,7 @@ impl<Arch> Debug for PageEntry<Arch> {
|
||||
|
||||
impl<Arch: MemoryManagementArch> PageEntry<Arch> {
|
||||
#[inline(always)]
|
||||
pub fn new(paddr: PhysAddr, flags: PageFlags<Arch>) -> Self {
|
||||
pub fn new(paddr: PhysAddr, flags: EntryFlags<Arch>) -> Self {
|
||||
Self {
|
||||
data: MMArch::make_entry(paddr, flags.data()),
|
||||
phantom: PhantomData,
|
||||
@ -420,12 +734,12 @@ impl<Arch: MemoryManagementArch> PageEntry<Arch> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flags(&self) -> PageFlags<Arch> {
|
||||
unsafe { PageFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) }
|
||||
pub fn flags(&self) -> EntryFlags<Arch> {
|
||||
unsafe { EntryFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_flags(&mut self, flags: PageFlags<Arch>) {
|
||||
pub fn set_flags(&mut self, flags: EntryFlags<Arch>) {
|
||||
self.data = (self.data & !Arch::ENTRY_FLAGS_MASK) | flags.data();
|
||||
}
|
||||
|
||||
@ -453,19 +767,19 @@ impl<Arch: MemoryManagementArch> PageEntry<Arch> {
|
||||
|
||||
/// 页表项的标志位
|
||||
#[derive(Copy, Clone, Hash)]
|
||||
pub struct PageFlags<Arch> {
|
||||
pub struct EntryFlags<Arch> {
|
||||
data: usize,
|
||||
phantom: PhantomData<Arch>,
|
||||
}
|
||||
|
||||
impl<Arch: MemoryManagementArch> Default for PageFlags<Arch> {
|
||||
impl<Arch: MemoryManagementArch> Default for EntryFlags<Arch> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<Arch: MemoryManagementArch> PageFlags<Arch> {
|
||||
impl<Arch: MemoryManagementArch> EntryFlags<Arch> {
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
let mut r = unsafe {
|
||||
@ -486,18 +800,19 @@ impl<Arch: MemoryManagementArch> PageFlags<Arch> {
|
||||
return r;
|
||||
}
|
||||
|
||||
/// 根据ProtFlags生成PageFlags
|
||||
/// 根据ProtFlags生成EntryFlags
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - prot_flags: 页的保护标志
|
||||
/// - user: 用户空间是否可访问
|
||||
pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> PageFlags<Arch> {
|
||||
let flags: PageFlags<Arch> = PageFlags::new()
|
||||
.set_user(user)
|
||||
.set_execute(prot_flags.contains(ProtFlags::PROT_EXEC))
|
||||
.set_write(prot_flags.contains(ProtFlags::PROT_WRITE));
|
||||
|
||||
pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> Self {
|
||||
let vm_flags = super::VmFlags::from(prot_flags);
|
||||
// let flags: EntryFlags<Arch> = EntryFlags::new()
|
||||
// .set_user(user)
|
||||
// .set_execute(prot_flags.contains(ProtFlags::PROT_EXEC))
|
||||
// .set_write(prot_flags.contains(ProtFlags::PROT_WRITE));
|
||||
let flags = Arch::vm_get_page_prot(vm_flags).set_user(user);
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -763,9 +1078,9 @@ impl<Arch: MemoryManagementArch> PageFlags<Arch> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arch: MemoryManagementArch> fmt::Debug for PageFlags<Arch> {
|
||||
impl<Arch: MemoryManagementArch> fmt::Debug for EntryFlags<Arch> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PageFlags")
|
||||
f.debug_struct("EntryFlags")
|
||||
.field("bits", &format_args!("{:#0x}", self.data))
|
||||
.field("present", &self.present())
|
||||
.field("has_write", &self.has_write())
|
||||
@ -861,7 +1176,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
pub unsafe fn map(
|
||||
&mut self,
|
||||
virt: VirtAddr,
|
||||
flags: PageFlags<Arch>,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<PageFlush<Arch>> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let phys: PhysAddr = self.frame_allocator.allocate_one()?;
|
||||
@ -875,9 +1190,9 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
let mut page_manager_guard: SpinLockGuard<'static, PageManager> =
|
||||
page_manager_lock_irqsave();
|
||||
if !page_manager_guard.contains(&phys) {
|
||||
page_manager_guard.insert(phys, Page::new(false))
|
||||
page_manager_guard.insert(phys, &Arc::new(Page::new(false, phys)))
|
||||
}
|
||||
|
||||
drop(page_manager_guard);
|
||||
return self.map_phys(virt, phys, flags);
|
||||
}
|
||||
|
||||
@ -886,7 +1201,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
&mut self,
|
||||
virt: VirtAddr,
|
||||
phys: PhysAddr,
|
||||
flags: PageFlags<Arch>,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<PageFlush<Arch>> {
|
||||
// 验证虚拟地址和物理地址是否对齐
|
||||
if !(virt.check_aligned(Arch::PAGE_SIZE) && phys.check_aligned(Arch::PAGE_SIZE)) {
|
||||
@ -926,8 +1241,8 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
// 清空这个页帧
|
||||
MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE);
|
||||
// 设置页表项的flags
|
||||
let flags: PageFlags<Arch> =
|
||||
PageFlags::new_page_table(virt.kind() == PageTableKind::User);
|
||||
let flags: EntryFlags<Arch> =
|
||||
EntryFlags::new_page_table(virt.kind() == PageTableKind::User);
|
||||
|
||||
// 把新分配的页表映射到当前页表
|
||||
table.set_entry(i, PageEntry::new(frame, flags));
|
||||
@ -943,7 +1258,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
pub unsafe fn map_huge_page(
|
||||
&mut self,
|
||||
virt: VirtAddr,
|
||||
flags: PageFlags<Arch>,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<PageFlush<Arch>> {
|
||||
// 验证虚拟地址是否对齐
|
||||
if !(virt.check_aligned(Arch::PAGE_SIZE)) {
|
||||
@ -1009,7 +1324,8 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE);
|
||||
|
||||
// 设置页表项的flags
|
||||
let flags: PageFlags<Arch> = PageFlags::new_page_table(virt.kind() == PageTableKind::User);
|
||||
let flags: EntryFlags<Arch> =
|
||||
EntryFlags::new_page_table(virt.kind() == PageTableKind::User);
|
||||
|
||||
table.set_entry(i, PageEntry::new(frame, flags));
|
||||
table.next_level_table(i)
|
||||
@ -1111,7 +1427,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
pub unsafe fn map_linearly(
|
||||
&mut self,
|
||||
phys: PhysAddr,
|
||||
flags: PageFlags<Arch>,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<(VirtAddr, PageFlush<Arch>)> {
|
||||
let virt: VirtAddr = Arch::phys_2_virt(phys)?;
|
||||
return self.map_phys(virt, phys, flags).map(|flush| (virt, flush));
|
||||
@ -1131,7 +1447,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
pub unsafe fn remap(
|
||||
&mut self,
|
||||
virt: VirtAddr,
|
||||
flags: PageFlags<Arch>,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<PageFlush<Arch>> {
|
||||
return self
|
||||
.visit(virt, |p1, i| {
|
||||
@ -1153,7 +1469,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 如果查找成功,返回物理地址和页表项的flags,否则返回None
|
||||
pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, PageFlags<Arch>)> {
|
||||
pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, EntryFlags<Arch>)> {
|
||||
let entry: PageEntry<Arch> = self.visit(virt, |p1, i| unsafe { p1.entry(i) })??;
|
||||
let paddr = entry.address().ok()?;
|
||||
let flags = entry.flags();
|
||||
@ -1192,7 +1508,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
&mut self,
|
||||
virt: VirtAddr,
|
||||
unmap_parents: bool,
|
||||
) -> Option<(PhysAddr, PageFlags<Arch>, PageFlush<Arch>)> {
|
||||
) -> Option<(PhysAddr, EntryFlags<Arch>, PageFlush<Arch>)> {
|
||||
if !virt.check_aligned(Arch::PAGE_SIZE) {
|
||||
error!("Try to unmap unaligned page: virt={:?}", virt);
|
||||
return None;
|
||||
@ -1240,7 +1556,7 @@ unsafe fn unmap_phys_inner<Arch: MemoryManagementArch>(
|
||||
table: &PageTable<Arch>,
|
||||
unmap_parents: bool,
|
||||
allocator: &mut impl FrameAllocator,
|
||||
) -> Option<(PhysAddr, PageFlags<Arch>)> {
|
||||
) -> Option<(PhysAddr, EntryFlags<Arch>)> {
|
||||
// 获取页表项的索引
|
||||
let i = table.index_of(vaddr)?;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::intrinsics::unlikely;
|
||||
use core::{intrinsics::unlikely, slice::from_raw_parts};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use log::error;
|
||||
@ -6,6 +6,7 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::base::block::SeekFrom,
|
||||
ipc::shm::ShmFlags,
|
||||
libs::align::{check_aligned, page_align_up},
|
||||
mm::MemoryManagementArch,
|
||||
@ -15,7 +16,7 @@ use crate::{
|
||||
use super::{
|
||||
allocator::page_frame::{PageFrameCount, VirtPageFrame},
|
||||
ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
|
||||
verify_area, VirtAddr, VmFlags,
|
||||
verify_area, MsFlags, VirtAddr, VmFlags,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
@ -154,6 +155,10 @@ impl From<MapFlags> for VmFlags {
|
||||
vm_flags |= VmFlags::VM_SYNC;
|
||||
}
|
||||
|
||||
if map_flags.contains(MapFlags::MAP_SHARED) {
|
||||
vm_flags |= VmFlags::VM_SHARED;
|
||||
}
|
||||
|
||||
vm_flags
|
||||
}
|
||||
}
|
||||
@ -296,8 +301,8 @@ impl Syscall {
|
||||
len: usize,
|
||||
prot_flags: usize,
|
||||
map_flags: usize,
|
||||
_fd: i32,
|
||||
_offset: 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);
|
||||
@ -311,11 +316,6 @@ impl Syscall {
|
||||
);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
// 暂时不支持除匿名页以外的映射
|
||||
if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
|
||||
error!("mmap: not support file mapping");
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
// 暂时不支持巨页映射
|
||||
if map_flags.contains(MapFlags::MAP_HUGETLB) {
|
||||
@ -323,14 +323,30 @@ impl Syscall {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
let current_address_space = AddressSpace::current()?;
|
||||
let start_page = current_address_space.write().map_anonymous(
|
||||
let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) {
|
||||
// 匿名映射
|
||||
current_address_space.write().map_anonymous(
|
||||
start_vaddr,
|
||||
len,
|
||||
prot_flags,
|
||||
map_flags,
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
)?
|
||||
} else {
|
||||
// 文件映射
|
||||
current_address_space.write().file_mapping(
|
||||
start_vaddr,
|
||||
len,
|
||||
prot_flags,
|
||||
map_flags,
|
||||
fd,
|
||||
offset,
|
||||
true,
|
||||
false,
|
||||
)?
|
||||
};
|
||||
|
||||
return Ok(start_page.virt_address().data());
|
||||
}
|
||||
|
||||
@ -390,7 +406,7 @@ impl Syscall {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let vma = vma.unwrap();
|
||||
let vm_flags = *vma.lock().vm_flags();
|
||||
let vm_flags = *vma.lock_irqsave().vm_flags();
|
||||
|
||||
// 暂时不支持巨页映射
|
||||
if vm_flags.contains(VmFlags::VM_HUGETLB) {
|
||||
@ -524,4 +540,115 @@ impl Syscall {
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// ## msync系统调用
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `start`:起始地址(已经对齐到页)
|
||||
/// - `len`:长度(已经对齐到页)
|
||||
/// - `flags`:标志
|
||||
pub fn msync(start: VirtAddr, len: usize, flags: usize) -> Result<usize, SystemError> {
|
||||
if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if unlikely(verify_area(start, len).is_err()) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
if unlikely(len == 0) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let mut start = start.data();
|
||||
let end = start + len;
|
||||
let flags = MsFlags::from_bits_truncate(flags);
|
||||
let mut unmapped_error = Ok(0);
|
||||
|
||||
if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if end < start {
|
||||
return Err(SystemError::ENOMEM);
|
||||
}
|
||||
|
||||
if start == end {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let current_address_space = AddressSpace::current()?;
|
||||
let mut err = Err(SystemError::ENOMEM);
|
||||
let mut next_vma = current_address_space
|
||||
.read()
|
||||
.mappings
|
||||
.find_nearest(VirtAddr::new(start));
|
||||
loop {
|
||||
if let Some(vma) = next_vma.clone() {
|
||||
let guard = vma.lock_irqsave();
|
||||
let vm_start = guard.region().start().data();
|
||||
let vm_end = guard.region().end().data();
|
||||
if start < vm_start {
|
||||
if flags == MsFlags::MS_ASYNC {
|
||||
break;
|
||||
}
|
||||
start = vm_start;
|
||||
if start >= vm_end {
|
||||
break;
|
||||
}
|
||||
unmapped_error = Err(SystemError::ENOMEM);
|
||||
}
|
||||
let vm_flags = *guard.vm_flags();
|
||||
if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) {
|
||||
err = Err(SystemError::EBUSY);
|
||||
break;
|
||||
}
|
||||
let file = guard.vm_file();
|
||||
let fstart = (start - vm_start)
|
||||
+ (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT);
|
||||
let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1;
|
||||
let old_start = start;
|
||||
start = vm_end;
|
||||
// log::info!("flags: {:?}", flags);
|
||||
// log::info!("vm_flags: {:?}", vm_flags);
|
||||
// log::info!("file: {:?}", file);
|
||||
if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) {
|
||||
if let Some(file) = file {
|
||||
let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap();
|
||||
file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap();
|
||||
err = file.write(len, unsafe {
|
||||
from_raw_parts(old_start as *mut u8, fend - fstart + 1)
|
||||
});
|
||||
file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap();
|
||||
if err.is_err() {
|
||||
break;
|
||||
} else if start >= end {
|
||||
err = unmapped_error;
|
||||
break;
|
||||
}
|
||||
next_vma = current_address_space
|
||||
.read()
|
||||
.mappings
|
||||
.find_nearest(VirtAddr::new(start));
|
||||
}
|
||||
} else {
|
||||
if start >= end {
|
||||
err = unmapped_error;
|
||||
break;
|
||||
}
|
||||
next_vma = current_address_space
|
||||
.read()
|
||||
.mappings
|
||||
.find_nearest(VirtAddr::new(vm_end));
|
||||
}
|
||||
} else {
|
||||
return Err(SystemError::ENOMEM);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
arch::{mm::PageMapper, CurrentIrqArch, MMArch},
|
||||
exception::InterruptArch,
|
||||
filesystem::vfs::file::File,
|
||||
libs::{
|
||||
align::page_align_up,
|
||||
rwlock::RwLock,
|
||||
@ -34,7 +35,7 @@ use super::{
|
||||
allocator::page_frame::{
|
||||
deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter,
|
||||
},
|
||||
page::{Flusher, InactiveFlusher, PageFlags, PageFlushAll},
|
||||
page::{EntryFlags, Flusher, InactiveFlusher, Page, PageFlushAll},
|
||||
syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags},
|
||||
MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags,
|
||||
};
|
||||
@ -178,23 +179,23 @@ impl InnerAddressSpace {
|
||||
for vma in self.mappings.vmas.iter() {
|
||||
// TODO: 增加对VMA是否为文件映射的判断,如果是的话,就跳过
|
||||
|
||||
let vma_guard: SpinLockGuard<'_, VMA> = vma.lock();
|
||||
let vma_guard: SpinLockGuard<'_, VMA> = vma.lock_irqsave();
|
||||
|
||||
// 仅拷贝VMA信息并添加反向映射,因为UserMapper克隆时已经分配了新的物理页
|
||||
let new_vma = LockedVMA::new(vma_guard.clone_info_only());
|
||||
new_guard.mappings.vmas.insert(new_vma.clone());
|
||||
// debug!("new vma: {:x?}", new_vma);
|
||||
let new_vma_guard = new_vma.lock();
|
||||
let new_vma_guard = new_vma.lock_irqsave();
|
||||
let new_mapper = &new_guard.user_mapper.utable;
|
||||
let mut anon_vma_guard = page_manager_lock_irqsave();
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
for page in new_vma_guard.pages().map(|p| p.virt_address()) {
|
||||
if let Some((paddr, _)) = new_mapper.translate(page) {
|
||||
let page = anon_vma_guard.get_mut(&paddr);
|
||||
page.insert_vma(new_vma.clone());
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(new_vma.clone());
|
||||
}
|
||||
}
|
||||
|
||||
drop(anon_vma_guard);
|
||||
drop(page_manager_guard);
|
||||
drop(vma_guard);
|
||||
drop(new_vma_guard);
|
||||
}
|
||||
@ -282,36 +283,138 @@ impl InnerAddressSpace {
|
||||
|
||||
// debug!("map_anonymous: len = {}", len);
|
||||
|
||||
let start_page: VirtPageFrame = if allocate_at_once {
|
||||
self.mmap(
|
||||
let start_page: VirtPageFrame = self.mmap(
|
||||
round_hint_to_min(start_vaddr),
|
||||
PageFrameCount::from_bytes(len).unwrap(),
|
||||
prot_flags,
|
||||
map_flags,
|
||||
move |page, count, flags, mapper, flusher| {
|
||||
VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)
|
||||
},
|
||||
)?
|
||||
if allocate_at_once {
|
||||
VMA::zeroed(page, count, vm_flags, flags, mapper, flusher, None, None)
|
||||
} else {
|
||||
self.mmap(
|
||||
round_hint_to_min(start_vaddr),
|
||||
PageFrameCount::from_bytes(len).unwrap(),
|
||||
prot_flags,
|
||||
map_flags,
|
||||
move |page, count, flags, _mapper, _flusher| {
|
||||
Ok(LockedVMA::new(VMA::new(
|
||||
VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE),
|
||||
vm_flags,
|
||||
flags,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)))
|
||||
}
|
||||
},
|
||||
)?
|
||||
};
|
||||
)?;
|
||||
|
||||
return Ok(start_page);
|
||||
}
|
||||
|
||||
/// 进行文件页映射
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `start_vaddr`:映射的起始地址
|
||||
/// - `len`:映射的长度
|
||||
/// - `prot_flags`:保护标志
|
||||
/// - `map_flags`:映射标志
|
||||
/// - `fd`:文件描述符
|
||||
/// - `offset`:映射偏移量
|
||||
/// - `round_to_min`:是否将`start_vaddr`对齐到`mmap_min`,如果为`true`,则当`start_vaddr`不为0时,会对齐到`mmap_min`,否则仅向下对齐到页边界
|
||||
/// - `allocate_at_once`:是否立即分配物理空间
|
||||
///
|
||||
/// ## 返回
|
||||
///
|
||||
/// 返回映射的起始虚拟页帧
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn file_mapping(
|
||||
&mut self,
|
||||
start_vaddr: VirtAddr,
|
||||
len: usize,
|
||||
prot_flags: ProtFlags,
|
||||
map_flags: MapFlags,
|
||||
fd: i32,
|
||||
offset: usize,
|
||||
round_to_min: bool,
|
||||
allocate_at_once: bool,
|
||||
) -> Result<VirtPageFrame, SystemError> {
|
||||
let allocate_at_once = if MMArch::PAGE_FAULT_ENABLED {
|
||||
allocate_at_once
|
||||
} else {
|
||||
true
|
||||
};
|
||||
// 用于对齐hint的函数
|
||||
let round_hint_to_min = |hint: VirtAddr| {
|
||||
// 先把hint向下对齐到页边界
|
||||
let addr = hint.data() & (!MMArch::PAGE_OFFSET_MASK);
|
||||
// debug!("map_anonymous: hint = {:?}, addr = {addr:#x}", hint);
|
||||
// 如果hint不是0,且hint小于DEFAULT_MMAP_MIN_ADDR,则对齐到DEFAULT_MMAP_MIN_ADDR
|
||||
if (addr != 0) && round_to_min && (addr < DEFAULT_MMAP_MIN_ADDR) {
|
||||
Some(VirtAddr::new(page_align_up(DEFAULT_MMAP_MIN_ADDR)))
|
||||
} else if addr == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(VirtAddr::new(addr))
|
||||
}
|
||||
};
|
||||
// debug!("map_anonymous: start_vaddr = {:?}", start_vaddr);
|
||||
// debug!("map_anonymous: len(no align) = {}", len);
|
||||
|
||||
let len = page_align_up(len);
|
||||
|
||||
let vm_flags = VmFlags::from(prot_flags)
|
||||
| VmFlags::from(map_flags)
|
||||
| VmFlags::VM_MAYREAD
|
||||
| VmFlags::VM_MAYWRITE
|
||||
| VmFlags::VM_MAYEXEC;
|
||||
|
||||
// debug!("map_anonymous: len = {}", len);
|
||||
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
|
||||
let file = fd_table_guard.get_file_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
// drop guard 以避免无法调度的问题
|
||||
drop(fd_table_guard);
|
||||
|
||||
// offset需要4K对齐
|
||||
if !offset & (MMArch::PAGE_SIZE - 1) == 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let pgoff = offset >> MMArch::PAGE_SHIFT;
|
||||
|
||||
let start_page: VirtPageFrame = self.mmap(
|
||||
round_hint_to_min(start_vaddr),
|
||||
PageFrameCount::from_bytes(len).unwrap(),
|
||||
prot_flags,
|
||||
map_flags,
|
||||
move |page, count, flags, mapper, flusher| {
|
||||
if allocate_at_once {
|
||||
VMA::zeroed(
|
||||
page,
|
||||
count,
|
||||
vm_flags,
|
||||
flags,
|
||||
mapper,
|
||||
flusher,
|
||||
file,
|
||||
Some(pgoff),
|
||||
)
|
||||
} else {
|
||||
Ok(LockedVMA::new(VMA::new(
|
||||
VirtRegion::new(page.virt_address(), count.data() * MMArch::PAGE_SIZE),
|
||||
vm_flags,
|
||||
flags,
|
||||
file,
|
||||
Some(pgoff),
|
||||
false,
|
||||
)))
|
||||
}
|
||||
},
|
||||
)?;
|
||||
return Ok(start_page);
|
||||
}
|
||||
|
||||
/// 向进程的地址空间映射页面
|
||||
///
|
||||
/// # 参数
|
||||
@ -333,7 +436,7 @@ impl InnerAddressSpace {
|
||||
F: FnOnce(
|
||||
VirtPageFrame,
|
||||
PageFrameCount,
|
||||
PageFlags<MMArch>,
|
||||
EntryFlags<MMArch>,
|
||||
&mut PageMapper,
|
||||
&mut dyn Flusher<MMArch>,
|
||||
) -> Result<Arc<LockedVMA>, SystemError>,
|
||||
@ -380,7 +483,7 @@ impl InnerAddressSpace {
|
||||
self.mappings.insert_vma(map_func(
|
||||
page,
|
||||
page_count,
|
||||
PageFlags::from_prot_flags(prot_flags, true),
|
||||
EntryFlags::from_prot_flags(prot_flags, true),
|
||||
&mut self.user_mapper.utable,
|
||||
flusher,
|
||||
)?);
|
||||
@ -479,9 +582,9 @@ impl InnerAddressSpace {
|
||||
let regions: Vec<Arc<LockedVMA>> = self.mappings.conflicts(to_unmap).collect::<Vec<_>>();
|
||||
|
||||
for r in regions {
|
||||
let r = r.lock().region;
|
||||
let r = r.lock_irqsave().region;
|
||||
let r = self.mappings.remove_vma(&r).unwrap();
|
||||
let intersection = r.lock().region().intersect(&to_unmap).unwrap();
|
||||
let intersection = r.lock_irqsave().region().intersect(&to_unmap).unwrap();
|
||||
let split_result = r.extract(intersection, &self.user_mapper.utable).unwrap();
|
||||
|
||||
// TODO: 当引入后备页映射后,这里需要增加通知文件的逻辑
|
||||
@ -533,10 +636,10 @@ impl InnerAddressSpace {
|
||||
|
||||
for r in regions {
|
||||
// debug!("mprotect: r: {:?}", r);
|
||||
let r = *r.lock().region();
|
||||
let r = *r.lock_irqsave().region();
|
||||
let r = self.mappings.remove_vma(&r).unwrap();
|
||||
|
||||
let intersection = r.lock().region().intersect(®ion).unwrap();
|
||||
let intersection = r.lock_irqsave().region().intersect(®ion).unwrap();
|
||||
let split_result = r
|
||||
.extract(intersection, mapper)
|
||||
.expect("Failed to extract VMA");
|
||||
@ -548,17 +651,16 @@ impl InnerAddressSpace {
|
||||
self.mappings.insert_vma(after);
|
||||
}
|
||||
|
||||
let mut r_guard = r.lock();
|
||||
let mut r_guard = r.lock_irqsave();
|
||||
// 如果VMA的保护标志不允许指定的修改,则返回错误
|
||||
if !r_guard.can_have_flags(prot_flags) {
|
||||
drop(r_guard);
|
||||
self.mappings.insert_vma(r.clone());
|
||||
return Err(SystemError::EACCES);
|
||||
}
|
||||
|
||||
r_guard.set_vm_flags(VmFlags::from(prot_flags));
|
||||
|
||||
let new_flags: PageFlags<MMArch> = r_guard
|
||||
let new_flags: EntryFlags<MMArch> = r_guard
|
||||
.flags()
|
||||
.set_execute(prot_flags.contains(ProtFlags::PROT_EXEC))
|
||||
.set_write(prot_flags.contains(ProtFlags::PROT_WRITE));
|
||||
@ -592,10 +694,10 @@ impl InnerAddressSpace {
|
||||
let regions = self.mappings.conflicts(region).collect::<Vec<_>>();
|
||||
|
||||
for r in regions {
|
||||
let r = *r.lock().region();
|
||||
let r = *r.lock_irqsave().region();
|
||||
let r = self.mappings.remove_vma(&r).unwrap();
|
||||
|
||||
let intersection = r.lock().region().intersect(®ion).unwrap();
|
||||
let intersection = r.lock_irqsave().region().intersect(®ion).unwrap();
|
||||
let split_result = r
|
||||
.extract(intersection, mapper)
|
||||
.expect("Failed to extract VMA");
|
||||
@ -768,7 +870,7 @@ impl UserMappings {
|
||||
#[allow(dead_code)]
|
||||
pub fn contains(&self, vaddr: VirtAddr) -> Option<Arc<LockedVMA>> {
|
||||
for v in self.vmas.iter() {
|
||||
let guard = v.lock();
|
||||
let guard = v.lock_irqsave();
|
||||
if guard.region.contains(vaddr) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
@ -788,13 +890,13 @@ impl UserMappings {
|
||||
pub fn find_nearest(&self, vaddr: VirtAddr) -> Option<Arc<LockedVMA>> {
|
||||
let mut nearest: Option<Arc<LockedVMA>> = None;
|
||||
for v in self.vmas.iter() {
|
||||
let guard = v.lock();
|
||||
let guard = v.lock_irqsave();
|
||||
if guard.region.contains(vaddr) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
if guard.region.start > vaddr
|
||||
if guard.region.start >= vaddr
|
||||
&& if let Some(ref nearest) = nearest {
|
||||
guard.region.start < nearest.lock().region.start
|
||||
guard.region.start < nearest.lock_irqsave().region.start
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -810,7 +912,7 @@ impl UserMappings {
|
||||
let r = self
|
||||
.vmas
|
||||
.iter()
|
||||
.filter(move |v| v.lock().region.intersect(&request).is_some())
|
||||
.filter(move |v| v.lock_irqsave().region.intersect(&request).is_some())
|
||||
.cloned();
|
||||
return r;
|
||||
}
|
||||
@ -932,7 +1034,7 @@ impl UserMappings {
|
||||
|
||||
/// 在当前进程的映射关系中,插入一个新的VMA。
|
||||
pub fn insert_vma(&mut self, vma: Arc<LockedVMA>) {
|
||||
let region = vma.lock().region;
|
||||
let region = vma.lock_irqsave().region;
|
||||
// 要求插入的地址范围必须是空闲的,也就是说,当前进程的地址空间中,不能有任何与之重叠的VMA。
|
||||
assert!(self.conflicts(region).next().is_none());
|
||||
self.reserve_hole(®ion);
|
||||
@ -952,7 +1054,7 @@ impl UserMappings {
|
||||
// 请注意,由于这里会对每个VMA加锁,因此性能很低
|
||||
let vma: Arc<LockedVMA> = self
|
||||
.vmas
|
||||
.drain_filter(|vma| vma.lock().region == *region)
|
||||
.drain_filter(|vma| vma.lock_irqsave().region == *region)
|
||||
.next()?;
|
||||
self.unreserve_hole(region);
|
||||
|
||||
@ -1002,7 +1104,7 @@ impl LockedVMA {
|
||||
id: LOCKEDVMA_ID_ALLOCATOR.alloc().unwrap(),
|
||||
vma: SpinLock::new(vma),
|
||||
});
|
||||
r.vma.lock().self_ref = Arc::downgrade(&r);
|
||||
r.vma.lock_irqsave().self_ref = Arc::downgrade(&r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1014,6 +1116,10 @@ impl LockedVMA {
|
||||
return self.vma.lock();
|
||||
}
|
||||
|
||||
pub fn lock_irqsave(&self) -> SpinLockGuard<VMA> {
|
||||
return self.vma.lock_irqsave();
|
||||
}
|
||||
|
||||
/// 调整当前VMA的页面的标志位
|
||||
///
|
||||
/// TODO:增加调整虚拟页映射的物理地址的功能
|
||||
@ -1024,11 +1130,11 @@ impl LockedVMA {
|
||||
///
|
||||
pub fn remap(
|
||||
&self,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: impl Flusher<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut guard = self.lock();
|
||||
let mut guard = self.lock_irqsave();
|
||||
for page in guard.region.pages() {
|
||||
// 暂时要求所有的页帧都已经映射到页表
|
||||
// TODO: 引入Lazy Mapping, 通过缺页中断来映射页帧,这里就不必要求所有的页帧都已经映射到页表了
|
||||
@ -1046,7 +1152,7 @@ impl LockedVMA {
|
||||
pub fn unmap(&self, mapper: &mut PageMapper, mut flusher: impl Flusher<MMArch>) {
|
||||
// todo: 如果当前vma与文件相关,完善文件相关的逻辑
|
||||
|
||||
let mut guard = self.lock();
|
||||
let mut guard = self.lock_irqsave();
|
||||
|
||||
// 获取物理页的anon_vma的守卫
|
||||
let mut page_manager_guard: SpinLockGuard<'_, crate::mm::page::PageManager> =
|
||||
@ -1059,12 +1165,13 @@ impl LockedVMA {
|
||||
.expect("Failed to unmap, beacuse of some page is not mapped");
|
||||
|
||||
// 从anon_vma中删除当前VMA
|
||||
let page = page_manager_guard.get_mut(&paddr);
|
||||
page.remove_vma(self);
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().remove_vma(self);
|
||||
|
||||
// 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页.
|
||||
if page.can_deallocate() {
|
||||
if page.read_irqsave().can_deallocate() {
|
||||
unsafe {
|
||||
drop(page);
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(paddr),
|
||||
PageFrameCount::new(1),
|
||||
@ -1076,10 +1183,19 @@ impl LockedVMA {
|
||||
flusher.consume(flush);
|
||||
}
|
||||
guard.mapped = false;
|
||||
|
||||
// 当vma对应共享文件的写映射时,唤醒脏页回写线程
|
||||
if guard.vm_file().is_some()
|
||||
&& guard
|
||||
.vm_flags()
|
||||
.contains(VmFlags::VM_SHARED | VmFlags::VM_WRITE)
|
||||
{
|
||||
crate::mm::page::PageReclaimer::wakeup_claim_thread();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mapped(&self) -> bool {
|
||||
return self.vma.lock().mapped;
|
||||
return self.vma.lock_irqsave().mapped;
|
||||
}
|
||||
|
||||
/// 将当前VMA进行切分,切分成3个VMA,分别是:
|
||||
@ -1091,7 +1207,7 @@ impl LockedVMA {
|
||||
assert!(region.start().check_aligned(MMArch::PAGE_SIZE));
|
||||
assert!(region.end().check_aligned(MMArch::PAGE_SIZE));
|
||||
|
||||
let mut guard = self.lock();
|
||||
let mut guard = self.lock_irqsave();
|
||||
{
|
||||
// 如果传入的region不在当前VMA的范围内,则直接返回None
|
||||
if unlikely(region.start() < guard.region.start() || region.end() > guard.region.end())
|
||||
@ -1134,25 +1250,27 @@ impl LockedVMA {
|
||||
// 重新设置before、after这两个VMA里面的物理页的anon_vma
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
if let Some(before) = before.clone() {
|
||||
let virt_iter = before.lock().region.iter_pages();
|
||||
let virt_iter = before.lock_irqsave().region.iter_pages();
|
||||
for frame in virt_iter {
|
||||
if let Some((paddr, _)) = utable.translate(frame.virt_address()) {
|
||||
let page = page_manager_guard.get_mut(&paddr);
|
||||
page.insert_vma(before.clone());
|
||||
page.remove_vma(self);
|
||||
before.lock().mapped = true;
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
let mut page_guard = page.write_irqsave();
|
||||
page_guard.insert_vma(before.clone());
|
||||
page_guard.remove_vma(self);
|
||||
before.lock_irqsave().mapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(after) = after.clone() {
|
||||
let virt_iter = after.lock().region.iter_pages();
|
||||
let virt_iter = after.lock_irqsave().region.iter_pages();
|
||||
for frame in virt_iter {
|
||||
if let Some((paddr, _)) = utable.translate(frame.virt_address()) {
|
||||
let page = page_manager_guard.get_mut(&paddr);
|
||||
page.insert_vma(after.clone());
|
||||
page.remove_vma(self);
|
||||
after.lock().mapped = true;
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
let mut page_guard = page.write_irqsave();
|
||||
page_guard.insert_vma(after.clone());
|
||||
page_guard.remove_vma(self);
|
||||
after.lock_irqsave().mapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1168,7 +1286,7 @@ impl LockedVMA {
|
||||
|
||||
/// 判断VMA是否为外部(非当前进程空间)的VMA
|
||||
pub fn is_foreign(&self) -> bool {
|
||||
let guard = self.lock();
|
||||
let guard = self.lock_irqsave();
|
||||
if let Some(space) = guard.user_address_space.clone() {
|
||||
if let Some(space) = space.upgrade() {
|
||||
return AddressSpace::is_current(&space);
|
||||
@ -1182,15 +1300,15 @@ impl LockedVMA {
|
||||
|
||||
/// 判断VMA是否可访问
|
||||
pub fn is_accessible(&self) -> bool {
|
||||
let guard = self.lock();
|
||||
let guard = self.lock_irqsave();
|
||||
let vm_access_flags: VmFlags = VmFlags::VM_READ | VmFlags::VM_WRITE | VmFlags::VM_EXEC;
|
||||
guard.vm_flags().intersects(vm_access_flags)
|
||||
}
|
||||
|
||||
/// 判断VMA是否为匿名映射
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
//TODO: 实现匿名映射判断逻辑,目前仅支持匿名映射
|
||||
true
|
||||
let guard = self.lock_irqsave();
|
||||
guard.vm_file.is_none()
|
||||
}
|
||||
|
||||
/// 判断VMA是否为大页映射
|
||||
@ -1236,13 +1354,17 @@ pub struct VMA {
|
||||
/// 虚拟内存区域标志
|
||||
vm_flags: VmFlags,
|
||||
/// VMA内的页帧的标志
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
/// VMA内的页帧是否已经映射到页表
|
||||
mapped: bool,
|
||||
/// VMA所属的用户地址空间
|
||||
user_address_space: Option<Weak<AddressSpace>>,
|
||||
self_ref: Weak<LockedVMA>,
|
||||
|
||||
vm_file: Option<Arc<File>>,
|
||||
/// VMA映射的文件部分相对于整个文件的偏移页数
|
||||
file_pgoff: Option<usize>,
|
||||
|
||||
provider: Provider,
|
||||
}
|
||||
|
||||
@ -1265,7 +1387,9 @@ impl VMA {
|
||||
pub fn new(
|
||||
region: VirtRegion,
|
||||
vm_flags: VmFlags,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
file: Option<Arc<File>>,
|
||||
pgoff: Option<usize>,
|
||||
mapped: bool,
|
||||
) -> Self {
|
||||
VMA {
|
||||
@ -1276,6 +1400,8 @@ impl VMA {
|
||||
user_address_space: None,
|
||||
self_ref: Weak::default(),
|
||||
provider: Provider::Allocated,
|
||||
vm_file: file,
|
||||
file_pgoff: pgoff,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1287,6 +1413,14 @@ impl VMA {
|
||||
return &self.vm_flags;
|
||||
}
|
||||
|
||||
pub fn vm_file(&self) -> Option<Arc<File>> {
|
||||
return self.vm_file.clone();
|
||||
}
|
||||
|
||||
pub fn address_space(&self) -> Option<Weak<AddressSpace>> {
|
||||
return self.user_address_space.clone();
|
||||
}
|
||||
|
||||
pub fn set_vm_flags(&mut self, vm_flags: VmFlags) {
|
||||
self.vm_flags = vm_flags;
|
||||
}
|
||||
@ -1299,6 +1433,10 @@ impl VMA {
|
||||
self.mapped = mapped;
|
||||
}
|
||||
|
||||
pub fn set_flags(&mut self) {
|
||||
self.flags = MMArch::vm_get_page_prot(self.vm_flags);
|
||||
}
|
||||
|
||||
/// # 拷贝当前VMA的内容
|
||||
///
|
||||
/// ### 安全性
|
||||
@ -1313,6 +1451,8 @@ impl VMA {
|
||||
user_address_space: self.user_address_space.clone(),
|
||||
self_ref: self.self_ref.clone(),
|
||||
provider: Provider::Allocated,
|
||||
file_pgoff: self.file_pgoff,
|
||||
vm_file: self.vm_file.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1325,14 +1465,21 @@ impl VMA {
|
||||
user_address_space: None,
|
||||
self_ref: Weak::default(),
|
||||
provider: Provider::Allocated,
|
||||
file_pgoff: self.file_pgoff,
|
||||
vm_file: self.vm_file.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flags(&self) -> PageFlags<MMArch> {
|
||||
pub fn flags(&self) -> EntryFlags<MMArch> {
|
||||
return self.flags;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn file_page_offset(&self) -> Option<usize> {
|
||||
return self.file_pgoff;
|
||||
}
|
||||
|
||||
pub fn pages(&self) -> VirtPageFrameIter {
|
||||
return VirtPageFrameIter::new(
|
||||
VirtPageFrame::new(self.region.start()),
|
||||
@ -1342,7 +1489,7 @@ impl VMA {
|
||||
|
||||
pub fn remap(
|
||||
&mut self,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: impl Flusher<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
@ -1395,7 +1542,7 @@ impl VMA {
|
||||
destination: VirtPageFrame,
|
||||
count: PageFrameCount,
|
||||
vm_flags: VmFlags,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: impl Flusher<MMArch>,
|
||||
) -> Result<Arc<LockedVMA>, SystemError> {
|
||||
@ -1417,23 +1564,22 @@ impl VMA {
|
||||
cur_dest = cur_dest.next();
|
||||
}
|
||||
|
||||
let r: Arc<LockedVMA> = LockedVMA::new(VMA {
|
||||
region: VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE),
|
||||
let r: Arc<LockedVMA> = LockedVMA::new(VMA::new(
|
||||
VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE),
|
||||
vm_flags,
|
||||
flags,
|
||||
mapped: true,
|
||||
user_address_space: None,
|
||||
self_ref: Weak::default(),
|
||||
provider: Provider::Allocated,
|
||||
});
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
));
|
||||
|
||||
// 将VMA加入到anon_vma中
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
cur_phy = phys;
|
||||
for _ in 0..count.data() {
|
||||
let paddr = cur_phy.phys_address();
|
||||
let page = page_manager_guard.get_mut(&paddr);
|
||||
page.insert_vma(r.clone());
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(r.clone());
|
||||
cur_phy = cur_phy.next();
|
||||
}
|
||||
|
||||
@ -1441,21 +1587,29 @@ impl VMA {
|
||||
}
|
||||
|
||||
/// 从页分配器中分配一些物理页,并把它们映射到指定的虚拟地址,然后创建VMA
|
||||
/// ## 参数
|
||||
///
|
||||
/// @param destination 要映射到的虚拟地址
|
||||
/// @param count 要映射的页帧数量
|
||||
/// @param flags 页面标志位
|
||||
/// @param mapper 页表映射器
|
||||
/// @param flusher 页表项刷新器
|
||||
/// - `destination`: 要映射到的虚拟地址
|
||||
/// - `page_count`: 要映射的页帧数量
|
||||
/// - `vm_flags`: VMA标志位
|
||||
/// - `flags`: 页面标志位
|
||||
/// - `mapper`: 页表映射器
|
||||
/// - `flusher`: 页表项刷新器
|
||||
/// - `file`: 映射文件
|
||||
/// - `pgoff`: 返回映射后的虚拟内存区域
|
||||
///
|
||||
/// @return 返回映射后的虚拟内存区域
|
||||
/// ## 返回值
|
||||
/// - 页面错误处理信息标志
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn zeroed(
|
||||
destination: VirtPageFrame,
|
||||
page_count: PageFrameCount,
|
||||
vm_flags: VmFlags,
|
||||
flags: PageFlags<MMArch>,
|
||||
flags: EntryFlags<MMArch>,
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: impl Flusher<MMArch>,
|
||||
file: Option<Arc<File>>,
|
||||
pgoff: Option<usize>,
|
||||
) -> Result<Arc<LockedVMA>, SystemError> {
|
||||
let mut cur_dest: VirtPageFrame = destination;
|
||||
// debug!(
|
||||
@ -1482,6 +1636,8 @@ impl VMA {
|
||||
),
|
||||
vm_flags,
|
||||
flags,
|
||||
file,
|
||||
pgoff,
|
||||
true,
|
||||
));
|
||||
drop(flusher);
|
||||
@ -1495,12 +1651,25 @@ impl VMA {
|
||||
let paddr = mapper.translate(frame.virt_address()).unwrap().0;
|
||||
|
||||
// 将VMA加入到anon_vma
|
||||
let page = page_manager_guard.get_mut(&paddr);
|
||||
page.insert_vma(r.clone());
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().insert_vma(r.clone());
|
||||
}
|
||||
// debug!("VMA::zeroed: done");
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
pub fn page_address(&self, page: &Arc<Page>) -> Result<VirtAddr, SystemError> {
|
||||
let page_guard = page.read_irqsave();
|
||||
let index = page_guard.index().unwrap();
|
||||
if index >= self.file_pgoff.unwrap() {
|
||||
let address =
|
||||
self.region.start + ((index - self.file_pgoff.unwrap()) << MMArch::PAGE_SHIFT);
|
||||
if address <= self.region.end() {
|
||||
return Ok(address);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VMA {
|
||||
|
@ -112,6 +112,7 @@ pub trait Scheduler {
|
||||
);
|
||||
|
||||
/// ## 选择接下来最适合运行的任务
|
||||
#[allow(dead_code)]
|
||||
fn pick_task(rq: &mut CpuRunQueue) -> Option<Arc<ProcessControlBlock>>;
|
||||
|
||||
/// ## 选择接下来最适合运行的任务
|
||||
|
@ -1104,6 +1104,12 @@ impl Syscall {
|
||||
|
||||
Self::shmctl(id, cmd, user_buf, from_user)
|
||||
}
|
||||
SYS_MSYNC => {
|
||||
let start = page_align_up(args[0]);
|
||||
let len = page_align_up(args[1]);
|
||||
let flags = args[2];
|
||||
Self::msync(VirtAddr::new(start), len, flags)
|
||||
}
|
||||
SYS_UTIMENSAT => Self::sys_utimensat(
|
||||
args[0] as i32,
|
||||
args[1] as *const u8,
|
||||
|
@ -2,7 +2,7 @@ use log::debug;
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::{vcpu::Vcpu, vm};
|
||||
use crate::mm::{kernel_mapper::KernelMapper, page::PageFlags, VirtAddr};
|
||||
use crate::mm::{kernel_mapper::KernelMapper, page::EntryFlags, VirtAddr};
|
||||
|
||||
/*
|
||||
* Address types:
|
||||
@ -152,7 +152,7 @@ fn hva_to_pfn(addr: u64, _atomic: bool, _writable: &mut bool) -> Result<u64, Sys
|
||||
return Ok(hpa.data() as u64 >> PAGE_SHIFT);
|
||||
}
|
||||
unsafe {
|
||||
mapper.map(hva, PageFlags::mmio_flags());
|
||||
mapper.map(hva, EntryFlags::mmio_flags());
|
||||
}
|
||||
let (hpa, _) = mapper.translate(hva).unwrap();
|
||||
return Ok(hpa.data() as u64 >> PAGE_SHIFT);
|
||||
|
1
user/apps/test_filemap/.gitignore
vendored
Normal file
1
user/apps/test_filemap/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test_filemap
|
20
user/apps/test_filemap/Makefile
Normal file
20
user/apps/test_filemap/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
ifeq ($(ARCH), x86_64)
|
||||
CROSS_COMPILE=x86_64-linux-musl-
|
||||
else ifeq ($(ARCH), riscv64)
|
||||
CROSS_COMPILE=riscv64-linux-musl-
|
||||
endif
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
.PHONY: all
|
||||
all: main.c
|
||||
$(CC) -static -o test_filemap main.c
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
mv test_filemap $(DADK_CURRENT_BUILD_DIR)/test_filemap
|
||||
|
||||
clean:
|
||||
rm test_filemap *.o
|
||||
|
||||
fmt:
|
61
user/apps/test_filemap/main.c
Normal file
61
user/apps/test_filemap/main.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// 打开文件
|
||||
int fd = open("example.txt", O_RDWR | O_CREAT | O_TRUNC, 0777);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
perror("open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
write(fd, "HelloWorld!", 11);
|
||||
char buf[12];
|
||||
buf[11] = '\0';
|
||||
close(fd);
|
||||
|
||||
fd = open("example.txt", O_RDWR);
|
||||
read(fd, buf, 11);
|
||||
printf("File content: %s\n", buf);
|
||||
|
||||
// 将文件映射到内存
|
||||
void *map = mmap(NULL, 11, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (map == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("mmap address: %p\n", map);
|
||||
|
||||
// 关闭文件描述符
|
||||
// close(fd);
|
||||
|
||||
// 访问和修改文件内容
|
||||
char *fileContent = (char *)map;
|
||||
printf("change 'H' to 'G'\n");
|
||||
fileContent[0] = 'G'; // 修改第一个字符为 'G'
|
||||
printf("mmap content: %s\n", fileContent);
|
||||
|
||||
// 解除映射
|
||||
printf("unmap\n");
|
||||
if (munmap(map, 11) == -1)
|
||||
{
|
||||
perror("munmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fd = open("example.txt", O_RDWR);
|
||||
read(fd, buf, 11);
|
||||
printf("File content: %s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
23
user/dadk/config/test_filemap-0.1.0.dadk
Normal file
23
user/dadk/config/test_filemap-0.1.0.dadk
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "test_filemap",
|
||||
"version": "0.1.0",
|
||||
"description": "测试filemap",
|
||||
"task_type": {
|
||||
"BuildFromSource": {
|
||||
"Local": {
|
||||
"path": "apps/test_filemap"
|
||||
}
|
||||
}
|
||||
},
|
||||
"depends": [],
|
||||
"build": {
|
||||
"build_command": "make install"
|
||||
},
|
||||
"clean": {
|
||||
"clean_command": "make clean"
|
||||
},
|
||||
"install": {
|
||||
"in_dragonos_path": "/bin"
|
||||
},
|
||||
"target_arch": ["x86_64"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user