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:
MemoryShore 2024-09-05 00:35:27 +08:00 committed by GitHub
parent 9fa0e95eee
commit cf7f801e1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 1791 additions and 352 deletions

View File

@ -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]

View File

@ -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)
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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 {

View File

@ -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);
}

View 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 {

View File

@ -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

View File

@ -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<_>>(),

View File

@ -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);
// 获取对应共享页管理信息

View File

@ -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
View 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()
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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(

View File

@ -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 {

View File

@ -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 => {

View File

@ -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);

View File

@ -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 虚拟地址范围

View File

@ -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));

View File

@ -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)?;

View File

@ -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;
}
}

View File

@ -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(&region).unwrap();
let intersection = r.lock_irqsave().region().intersect(&region).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(&region).unwrap();
let intersection = r.lock_irqsave().region().intersect(&region).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(&region);
@ -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 {

View File

@ -112,6 +112,7 @@ pub trait Scheduler {
);
/// ## 选择接下来最适合运行的任务
#[allow(dead_code)]
fn pick_task(rq: &mut CpuRunQueue) -> Option<Arc<ProcessControlBlock>>;
/// ## 选择接下来最适合运行的任务

View File

@ -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,

View File

@ -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
View File

@ -0,0 +1 @@
test_filemap

View 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:

View 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;
}

View 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"]
}