mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 16:16:16 +04:00
delay mapping file
This commit is contained in:
parent
88e1055eed
commit
a25c8132fe
@ -40,9 +40,10 @@ impl<T: FrameAllocator> MemoryHandler for Delay<T> {
|
||||
let data = Vec::from(pt.get_page_slice_mut(addr));
|
||||
with(&mut || {
|
||||
let target = self.allocator.alloc().expect("failed to alloc frame");
|
||||
let target_data = pt.get_page_slice_mut(addr);
|
||||
let entry = pt.map(addr, target);
|
||||
target_data.copy_from_slice(&data);
|
||||
attr.apply(entry);
|
||||
pt.get_page_slice_mut(addr).copy_from_slice(&data);
|
||||
});
|
||||
} else {
|
||||
// delay map
|
||||
|
108
crate/memory/src/memory_set/handler/file.rs
Normal file
108
crate/memory/src/memory_set/handler/file.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use super::*;
|
||||
|
||||
/// Delay mapping a page to an area of a file.
|
||||
#[derive(Clone)]
|
||||
pub struct File<F, T> {
|
||||
pub file: F,
|
||||
pub mem_start: usize,
|
||||
pub file_start: usize,
|
||||
pub file_end: usize,
|
||||
pub allocator: T,
|
||||
}
|
||||
|
||||
pub trait Read: Clone + Send + Sync + 'static {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize;
|
||||
}
|
||||
|
||||
impl<F: Read, T: FrameAllocator> MemoryHandler for File<F, T> {
|
||||
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn map(&self, pt: &mut PageTable, addr: usize, attr: &MemoryAttr) {
|
||||
let entry = pt.map(addr, 0);
|
||||
entry.set_present(false);
|
||||
attr.apply(entry);
|
||||
}
|
||||
|
||||
fn unmap(&self, pt: &mut PageTable, addr: usize) {
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
if entry.present() {
|
||||
self.allocator.dealloc(entry.target());
|
||||
}
|
||||
|
||||
// PageTable::unmap requires page to be present
|
||||
entry.set_present(true);
|
||||
pt.unmap(addr);
|
||||
}
|
||||
|
||||
fn clone_map(
|
||||
&self,
|
||||
pt: &mut PageTable,
|
||||
with: &Fn(&mut FnMut()),
|
||||
addr: usize,
|
||||
attr: &MemoryAttr,
|
||||
) {
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
if entry.present() && !attr.readonly {
|
||||
// eager map and copy data
|
||||
let data = Vec::from(pt.get_page_slice_mut(addr));
|
||||
with(&mut || {
|
||||
let target = self.allocator.alloc().expect("failed to alloc frame");
|
||||
let target_data = pt.get_page_slice_mut(addr);
|
||||
let entry = pt.map(addr, target);
|
||||
target_data.copy_from_slice(&data);
|
||||
attr.apply(entry);
|
||||
});
|
||||
} else {
|
||||
// delay map
|
||||
with(&mut || self.map(pt, addr, attr));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_page_fault(&self, pt: &mut PageTable, addr: usize) -> bool {
|
||||
let addr = addr & !(PAGE_SIZE - 1);
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
if entry.present() {
|
||||
return false;
|
||||
}
|
||||
let frame = self.allocator.alloc().expect("failed to alloc frame");
|
||||
entry.set_target(frame);
|
||||
entry.set_present(true);
|
||||
let writable = entry.writable();
|
||||
entry.set_writable(true);
|
||||
entry.update();
|
||||
|
||||
self.fill_data(pt, addr);
|
||||
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
entry.set_writable(writable);
|
||||
entry.update();
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Read, T: FrameAllocator> File<F, T> {
|
||||
fn fill_data(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let data = pt.get_page_slice_mut(addr);
|
||||
let file_offset = addr + self.file_start - self.mem_start;
|
||||
let read_size = (self.file_end as isize - file_offset as isize)
|
||||
.min(PAGE_SIZE as isize)
|
||||
.max(0) as usize;
|
||||
let read_size = self.file.read_at(file_offset, &mut data[..read_size]);
|
||||
if read_size != PAGE_SIZE {
|
||||
data[read_size..].iter_mut().for_each(|x| *x = 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T> Debug for File<F, T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
f.debug_struct("FileHandler")
|
||||
.field("mem_start", &self.mem_start)
|
||||
.field("file_start", &self.file_start)
|
||||
.field("file_end", &self.file_end)
|
||||
.finish()
|
||||
}
|
||||
}
|
@ -42,8 +42,10 @@ pub trait FrameAllocator: Debug + Clone + Send + Sync + 'static {
|
||||
mod byframe;
|
||||
mod delay;
|
||||
mod linear;
|
||||
mod file;
|
||||
//mod swap;
|
||||
|
||||
pub use self::byframe::ByFrame;
|
||||
pub use self::delay::Delay;
|
||||
pub use self::linear::Linear;
|
||||
pub use self::file::{File, Read};
|
||||
|
@ -116,4 +116,8 @@ impl FileHandle {
|
||||
pub fn io_control(&self, cmd: u32, arg: usize) -> Result<()> {
|
||||
self.inode.io_control(cmd, arg)
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Arc<INode> {
|
||||
self.inode.clone()
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,13 @@ use xmas_elf::{
|
||||
|
||||
use crate::arch::interrupt::{Context, TrapFrame};
|
||||
use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH};
|
||||
use crate::memory::{ByFrame, Delay, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
|
||||
use crate::memory::{
|
||||
ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read,
|
||||
};
|
||||
use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
|
||||
|
||||
use super::abi::{self, ProcInitInfo};
|
||||
use rcore_fs::vfs::INode;
|
||||
|
||||
// TODO: avoid pub
|
||||
pub struct Thread {
|
||||
@ -128,19 +131,25 @@ impl Thread {
|
||||
/// Construct virtual memory of a new user process from ELF `data`.
|
||||
/// Return `(MemorySet, entry_point, ustack_top)`
|
||||
pub fn new_user_vm(
|
||||
data: &[u8],
|
||||
inode: &Arc<INode>,
|
||||
exec_path: &str,
|
||||
mut args: Vec<String>,
|
||||
envs: Vec<String>,
|
||||
) -> (MemorySet, usize, usize) {
|
||||
) -> Result<(MemorySet, usize, usize), &'static str> {
|
||||
// Read data
|
||||
use crate::fs::INodeExt;
|
||||
let data = inode
|
||||
.read_as_vec()
|
||||
.map_err(|_| "failed to read from INode")?;
|
||||
|
||||
// Parse ELF
|
||||
let elf = ElfFile::new(data).expect("failed to read elf");
|
||||
let elf = ElfFile::new(&data)?;
|
||||
|
||||
// Check ELF type
|
||||
match elf.header.pt2.type_().as_type() {
|
||||
header::Type::Executable => {}
|
||||
header::Type::SharedObject => {}
|
||||
_ => panic!("ELF is not executable or shared object"),
|
||||
_ => return Err("ELF is not executable or shared object"),
|
||||
}
|
||||
|
||||
// Check ELF arch
|
||||
@ -153,7 +162,7 @@ impl Thread {
|
||||
header::Machine::Other(243) => {}
|
||||
#[cfg(target_arch = "mips")]
|
||||
header::Machine::Mips => {}
|
||||
machine @ _ => panic!("invalid elf arch: {:?}", machine),
|
||||
machine @ _ => return Err("invalid ELF arch"),
|
||||
}
|
||||
|
||||
// Check interpreter (for dynamic link)
|
||||
@ -161,18 +170,17 @@ impl Thread {
|
||||
// assuming absolute path
|
||||
let inode = crate::fs::ROOT_INODE
|
||||
.lookup_follow(loader_path, FOLLOW_MAX_DEPTH)
|
||||
.expect("interpreter not found");
|
||||
let buf = inode.read_as_vec().expect("failed to load interpreter");
|
||||
.map_err(|_| "interpreter not found")?;
|
||||
// modify args for loader
|
||||
args[0] = exec_path.into();
|
||||
args.insert(0, loader_path.into());
|
||||
// Elf loader should not have INTERP
|
||||
// No infinite loop
|
||||
return Thread::new_user_vm(buf.as_slice(), exec_path, args, envs);
|
||||
return Thread::new_user_vm(&inode, exec_path, args, envs);
|
||||
}
|
||||
|
||||
// Make page table
|
||||
let mut vm = elf.make_memory_set();
|
||||
let mut vm = elf.make_memory_set(inode);
|
||||
|
||||
// User stack
|
||||
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE};
|
||||
@ -219,17 +227,17 @@ impl Thread {
|
||||
trace!("{:#x?}", vm);
|
||||
|
||||
let entry_addr = elf.header.pt2.entry_point() as usize;
|
||||
(vm, entry_addr, ustack_top)
|
||||
Ok((vm, entry_addr, ustack_top))
|
||||
}
|
||||
|
||||
/// Make a new user process from ELF `data`
|
||||
pub fn new_user(
|
||||
data: &[u8],
|
||||
inode: &Arc<INode>,
|
||||
exec_path: &str,
|
||||
mut args: Vec<String>,
|
||||
envs: Vec<String>,
|
||||
) -> Box<Thread> {
|
||||
let (vm, entry_addr, ustack_top) = Self::new_user_vm(data, exec_path, args, envs);
|
||||
let (vm, entry_addr, ustack_top) = Self::new_user_vm(inode, exec_path, args, envs).unwrap();
|
||||
|
||||
let kstack = KernelStack::new();
|
||||
|
||||
@ -307,7 +315,8 @@ impl Thread {
|
||||
threads: Vec::new(),
|
||||
child_exit: Arc::new(Condvar::new()),
|
||||
child_exit_code: BTreeMap::new(),
|
||||
}.add_to_table();
|
||||
}
|
||||
.add_to_table();
|
||||
// link to parent
|
||||
proc.children.push(Arc::downgrade(&new_proc));
|
||||
|
||||
@ -382,10 +391,12 @@ trait ToMemoryAttr {
|
||||
impl ToMemoryAttr for Flags {
|
||||
fn to_attr(&self) -> MemoryAttr {
|
||||
let mut flags = MemoryAttr::default().user();
|
||||
// FIXME: handle readonly
|
||||
if self.is_execute() {
|
||||
flags = flags.execute();
|
||||
}
|
||||
if !self.is_write() {
|
||||
flags = flags.readonly();
|
||||
}
|
||||
flags
|
||||
}
|
||||
}
|
||||
@ -393,7 +404,7 @@ impl ToMemoryAttr for Flags {
|
||||
/// Helper functions to process ELF file
|
||||
trait ElfExt {
|
||||
/// Generate a MemorySet according to the ELF file.
|
||||
fn make_memory_set(&self) -> MemorySet;
|
||||
fn make_memory_set(&self, inode: &Arc<INode>) -> MemorySet;
|
||||
|
||||
/// Get interpreter string if it has.
|
||||
fn get_interpreter(&self) -> Result<&str, &str>;
|
||||
@ -403,7 +414,7 @@ trait ElfExt {
|
||||
}
|
||||
|
||||
impl ElfExt for ElfFile<'_> {
|
||||
fn make_memory_set(&self) -> MemorySet {
|
||||
fn make_memory_set(&self, inode: &Arc<INode>) -> MemorySet {
|
||||
debug!("creating MemorySet from ELF");
|
||||
let mut ms = MemorySet::new();
|
||||
|
||||
@ -411,33 +422,19 @@ impl ElfExt for ElfFile<'_> {
|
||||
if ph.get_type() != Ok(Type::Load) {
|
||||
continue;
|
||||
}
|
||||
let virt_addr = ph.virtual_addr() as usize;
|
||||
let mem_size = ph.mem_size() as usize;
|
||||
let data = match ph.get_data(self).unwrap() {
|
||||
SegmentData::Undefined(data) => data,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Get target slice
|
||||
let target = {
|
||||
ms.push(
|
||||
virt_addr,
|
||||
virt_addr + mem_size,
|
||||
ph.flags().to_attr(),
|
||||
ByFrame::new(GlobalFrameAlloc),
|
||||
"elf",
|
||||
);
|
||||
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
|
||||
};
|
||||
// Copy data
|
||||
unsafe {
|
||||
ms.with(|| {
|
||||
if data.len() != 0 {
|
||||
target[..data.len()].copy_from_slice(data);
|
||||
}
|
||||
target[data.len()..].iter_mut().for_each(|x| *x = 0);
|
||||
});
|
||||
}
|
||||
ms.push(
|
||||
ph.virtual_addr() as usize,
|
||||
ph.virtual_addr() as usize + ph.mem_size() as usize,
|
||||
ph.flags().to_attr(),
|
||||
File {
|
||||
file: INodeForMap(inode.clone()),
|
||||
mem_start: ph.virtual_addr() as usize,
|
||||
file_start: ph.offset() as usize,
|
||||
file_end: ph.offset() as usize + ph.file_size() as usize,
|
||||
allocator: GlobalFrameAlloc,
|
||||
},
|
||||
"elf",
|
||||
);
|
||||
}
|
||||
ms
|
||||
}
|
||||
@ -479,3 +476,12 @@ impl ElfExt for ElfFile<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct INodeForMap(pub Arc<INode>);
|
||||
|
||||
impl Read for INodeForMap {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
|
||||
self.0.read_at(offset, buf).unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -30,9 +30,8 @@ pub fn add_user_shell() {
|
||||
let init_args = vec!["busybox".into(), "ash".into()];
|
||||
|
||||
if let Ok(inode) = ROOT_INODE.lookup(init_shell) {
|
||||
let data = inode.read_as_vec().unwrap();
|
||||
processor().manager().add(Thread::new_user(
|
||||
data.as_slice(),
|
||||
&inode,
|
||||
init_shell,
|
||||
init_args,
|
||||
init_envs,
|
||||
@ -46,9 +45,8 @@ pub fn add_user_shell() {
|
||||
pub fn add_user_shell() {
|
||||
let cmdline = CMDLINE.read();
|
||||
let inode = ROOT_INODE.lookup(&cmdline).unwrap();
|
||||
let data = inode.read_as_vec().unwrap();
|
||||
processor().manager().add(Thread::new_user(
|
||||
data.as_slice(),
|
||||
&inode,
|
||||
cmdline.split(' ').map(|s| s.into()).collect(),
|
||||
Vec::new(),
|
||||
));
|
||||
@ -66,16 +64,14 @@ pub extern "C" fn shell(_arg: usize) -> ! {
|
||||
continue;
|
||||
}
|
||||
let name = cmd.trim().split(' ').next().unwrap();
|
||||
if let Ok(file) = ROOT_INODE.lookup(name) {
|
||||
let data = file.read_as_vec().unwrap();
|
||||
let _pid = processor().manager().add(Thread::new_user(
|
||||
data.as_slice(),
|
||||
if let Ok(inode) = ROOT_INODE.lookup(name) {
|
||||
let _tid = processor().manager().add(Thread::new_user(
|
||||
&inode,
|
||||
&cmd,
|
||||
cmd.split(' ').map(|s| s.into()).collect(),
|
||||
Vec::new(),
|
||||
));
|
||||
// TODO: wait until process exits, or use user land shell completely
|
||||
//unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
||||
} else {
|
||||
println!("Program not exist");
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rcore_memory::memory_set::handler::{ByFrame, Delay};
|
||||
use rcore_memory::memory_set::handler::{ByFrame, Delay, File};
|
||||
use rcore_memory::memory_set::MemoryAttr;
|
||||
use rcore_memory::paging::PageTable;
|
||||
use rcore_memory::Page;
|
||||
@ -46,35 +46,25 @@ pub fn sys_mmap(
|
||||
addr,
|
||||
addr + len,
|
||||
prot.to_attr(),
|
||||
// ByFrame::new(GlobalFrameAlloc), //eagle mmap mode
|
||||
Delay::new(GlobalFrameAlloc),
|
||||
"mmap_anon",
|
||||
);
|
||||
//init with zero for eagle mmap mode
|
||||
// let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) };
|
||||
// for x in data {
|
||||
// *x = 0;
|
||||
// }
|
||||
return Ok(addr);
|
||||
} else {
|
||||
// only check
|
||||
let _ = proc.get_file(fd)?;
|
||||
|
||||
// TODO: delay mmap file
|
||||
let inode = proc.get_file(fd)?.inode();
|
||||
proc.vm.push(
|
||||
addr,
|
||||
addr + len,
|
||||
prot.to_attr(),
|
||||
ByFrame::new(GlobalFrameAlloc),
|
||||
File {
|
||||
file: INodeForMap(inode),
|
||||
mem_start: addr,
|
||||
file_start: offset,
|
||||
file_end: offset + len,
|
||||
allocator: GlobalFrameAlloc,
|
||||
},
|
||||
"mmap_file",
|
||||
);
|
||||
let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) };
|
||||
let file = proc.get_file(fd)?;
|
||||
let read_len = file.read_at(offset, data)?;
|
||||
if read_len != data.len() {
|
||||
// use count() to consume the iterator
|
||||
data[read_len..].iter_mut().map(|x| *x = 0).count();
|
||||
}
|
||||
return Ok(addr);
|
||||
}
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<Sys
|
||||
SYS_DUP2 => sys_dup2(args[0], args[1]),
|
||||
SYS_ALARM => unimplemented("alarm", Ok(0)),
|
||||
SYS_FORK => sys_fork(tf),
|
||||
SYS_VFORK => sys_fork(tf), // use fork for vfork
|
||||
SYS_VFORK => sys_vfork(tf),
|
||||
SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8),
|
||||
SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]),
|
||||
SYS_RMDIR => sys_rmdir(args[0] as *const u8),
|
||||
|
@ -13,6 +13,10 @@ pub fn sys_fork(tf: &TrapFrame) -> SysResult {
|
||||
Ok(pid)
|
||||
}
|
||||
|
||||
pub fn sys_vfork(tf: &TrapFrame) -> SysResult {
|
||||
sys_fork(tf)
|
||||
}
|
||||
|
||||
/// Create a new thread in the current process.
|
||||
/// The new thread's stack pointer will be set to `newsp`,
|
||||
/// and thread pointer will be set to `newtls`.
|
||||
@ -168,16 +172,15 @@ pub fn sys_exec(
|
||||
|
||||
// Read program file
|
||||
let inode = proc.lookup_inode(&path)?;
|
||||
let data = inode.read_as_vec()?;
|
||||
|
||||
// Make new Thread
|
||||
let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(data.as_slice(), &path, args, envs);
|
||||
let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(&inode, &path, args, envs).unwrap();
|
||||
|
||||
// Activate new page table
|
||||
unsafe {
|
||||
vm.activate();
|
||||
}
|
||||
core::mem::swap(&mut proc.vm, &mut vm);
|
||||
unsafe {
|
||||
proc.vm.activate();
|
||||
}
|
||||
|
||||
// Modify the TrapFrame
|
||||
*tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
|
||||
|
Loading…
Reference in New Issue
Block a user