From 731d6319e43985ca0e9a616ab4ed49230aaa325e Mon Sep 17 00:00:00 2001 From: WangRunji <wangrunji0408@163.com> Date: Fri, 18 May 2018 11:49:27 +0800 Subject: [PATCH] Can load user programs from sfs.img (hard linked). --- Cargo.toml | 1 + Makefile | 3 +++ src/fs.rs | 50 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +++ src/process/mod.rs | 52 +++++++++++++++------------------------ src/process/process.rs | 28 ++++++++++----------- src/process/processor.rs | 19 +++++++------- user/hello.o | Bin 40914 -> 0 bytes 8 files changed, 102 insertions(+), 55 deletions(-) create mode 100644 src/fs.rs delete mode 100644 user/hello.o diff --git a/Cargo.toml b/Cargo.toml index ba3cd0d..a27d98d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ linked_list_allocator = "0.5.0" redox_syscall = "0.1.37" xmas-elf = "0.6" arrayvec = { version = "0.4.7", default-features = false } +simple-filesystem = { path = "../simple-filesystem" } [build-dependencies] cc = "1.0" diff --git a/Makefile b/Makefile index f3c31ae..9db3fe0 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,9 @@ clean: run: $(iso) @qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11 +debug: $(iso) + @qemu-system-$(arch) $(qemu_opts) -s -S & + iso: $(iso) build: iso diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..e53a2d4 --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,50 @@ +use simple_filesystem::*; +use alloc::boxed::Box; +use process; + +extern { + fn _binary_user_sfs_img_start(); + fn _binary_user_sfs_img_end(); + fn _binary_user_forktest_start(); + fn _binary_user_forktest_end(); +} + +struct MemBuf(&'static [u8]); + +impl MemBuf { + unsafe fn new(begin: unsafe extern fn(), end: unsafe extern fn()) -> Self { + use core::slice; + MemBuf(slice::from_raw_parts(begin as *const u8, end as usize - begin as usize)) + } +} + +impl Device for MemBuf { + fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize> { + let slice = self.0; + let len = buf.len().min(slice.len() - offset); + buf[..len].copy_from_slice(&slice[offset..offset + len]); + Some(len) + } + fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize> { + None + } +} + +pub fn load_sfs() { + let slice = unsafe { MemBuf::new(_binary_user_sfs_img_start, _binary_user_sfs_img_end) }; + let sfs = SimpleFileSystem::open(Box::new(slice)).unwrap(); + let root = sfs.root_inode(); + let files = root.borrow().list().unwrap(); + debug!("Loading programs: {:?}", files); + + for name in files.iter().filter(|&f| f != "." && f != "..") { + static mut BUF: [u8; 64 << 12] = [0; 64 << 12]; + let file = root.borrow().lookup(name.as_str()).unwrap(); + let len = file.borrow().read_at(0, unsafe { &mut BUF }).unwrap(); + process::add_user_process(name.as_str(), unsafe { &BUF[..len] }); + } + + process::add_user_process("forktest", unsafe { MemBuf::new(_binary_user_forktest_start, _binary_user_forktest_end).0 }); + + process::print(); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 919c604..181b54b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ extern crate bit_field; extern crate syscall as redox_syscall; extern crate xmas_elf; extern crate arrayvec; +extern crate simple_filesystem; #[macro_use] // print! mod io; @@ -45,6 +46,7 @@ mod macros; mod consts; mod process; mod syscall; +mod fs; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] @@ -81,6 +83,8 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // arch::smp::start_other_cores(&acpi, &mut memory_controller); process::init(memory_controller); + fs::load_sfs(); + unsafe{ arch::interrupt::enable(); } // 直接进入用户态暂不可用:内核代码用户不可访问 diff --git a/src/process/mod.rs b/src/process/mod.rs index a838c6b..15bb749 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -1,6 +1,7 @@ use memory::MemoryController; use spin::{Once, Mutex}; use core::slice; +use alloc::String; use self::process::*; use self::processor::*; @@ -15,48 +16,20 @@ mod processor; /// * Debug: 用于Debug输出 use arch::interrupt::TrapFrame; -// TODO: 使用宏来更优雅地导入符号,现在会有编译错误 -// -// #![feature(concat_idents)] -// -// macro_rules! binary_symbol { -// ($name: ident) => { -// extern { -// fn concat_idents!(_binary_user_, $name, _start)(); -// fn concat_idents!(_binary_user_, $name, _end)(); -// } -// }; -// } -// -// binary_symbol!(forktest); - -#[cfg(feature = "link_user_program")] -extern { - fn _binary_user_forktest_start(); - fn _binary_user_forktest_end(); - fn _binary_hello_start(); - fn _binary_hello_end(); -} - - pub fn init(mut mc: MemoryController) { PROCESSOR.call_once(|| {Mutex::new({ let initproc = Process::new_init(&mut mc); let idleproc = Process::new("idle", idle_thread, &mut mc); - #[cfg(feature = "link_user_program")] -// let forktest = Process::new_user(_binary_user_forktest_start as usize, -// _binary_user_forktest_end as usize, &mut mc); - let hello = Process::new_user(_binary_hello_start as usize, - _binary_hello_end as usize, &mut mc); - let mut processor = Processor::new(mc); + let mut processor = Processor::new(); processor.add(initproc); processor.add(idleproc); - processor.add(hello); processor })}); + MC.call_once(|| Mutex::new(mc)); } static PROCESSOR: Once<Mutex<Processor>> = Once::new(); +static MC: Once<Mutex<MemoryController>> = Once::new(); /// Called by timer handler in arch /// 设置rsp,指向接下来要执行线程的 内核栈顶 @@ -77,7 +50,10 @@ extern fn idle_thread() { /// Fork the current process pub fn sys_fork(tf: &TrapFrame) -> i32 { - PROCESSOR.try().unwrap().lock().fork(tf); + let mut processor = PROCESSOR.try().unwrap().lock(); + let mut mc = MC.try().unwrap().lock(); + let new = processor.current().fork(tf, &mut mc); + processor.add(new); 0 } @@ -99,4 +75,16 @@ pub fn sys_exit(rsp: &mut usize, error_code: usize) -> i32 { processor.schedule(rsp); processor.exit(pid, error_code); 0 +} + +pub fn add_user_process(name: &str, data: &[u8]) { + let mut processor = PROCESSOR.try().unwrap().lock(); + let mut mc = MC.try().unwrap().lock(); + let mut new = Process::new_user(data, &mut mc); + new.name = String::from(name); + processor.add(new); +} + +pub fn print() { + debug!("{:#x?}", *PROCESSOR.try().unwrap().lock()); } \ No newline at end of file diff --git a/src/process/process.rs b/src/process/process.rs index 03291ef..7dd18d6 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -2,13 +2,12 @@ use super::*; use memory::{self, Stack, InactivePageTable}; use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2}; use core::slice; -use alloc::rc::Rc; -use rlibc::memcpy; +use alloc::{rc::Rc, String}; #[derive(Debug)] pub struct Process { pub(in process) pid: Pid, - name: &'static str, + pub(in process) name: String, kstack: Stack, pub(in process) memory_set: Option<MemorySet>, pub(in process) page_table: Option<InactivePageTable>, @@ -26,14 +25,14 @@ pub enum Status { impl Process { /// Make a new kernel thread - pub fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Self { + pub fn new(name: &str, entry: extern fn(), mc: &mut MemoryController) -> Self { let kstack = mc.alloc_stack(7).unwrap(); let tf = TrapFrame::new_kernel_thread(entry, kstack.top()); let rsp = kstack.push_at_top(tf); Process { pid: 0, - name, + name: String::from(name), kstack, memory_set: None, page_table: None, @@ -49,7 +48,7 @@ impl Process { assert_has_not_been_called!(); Process { pid: 0, - name: "init", + name: String::from("init"), kstack: mc.kernel_stack.take().unwrap(), memory_set: None, page_table: None, @@ -62,10 +61,10 @@ impl Process { /// Make a new user thread /// The program elf data is placed at [begin, end) /// uCore x86 32bit program is planned to be supported. - pub fn new_user(begin: usize, end: usize, mc: &mut MemoryController) -> Self { + pub fn new_user(data: &[u8], mc: &mut MemoryController) -> Self { // Parse elf - let slice = unsafe{ slice::from_raw_parts(begin as *const u8, end - begin) }; - let elf = ElfFile::new(slice).expect("failed to read elf"); + let begin = data.as_ptr() as usize; + let elf = ElfFile::new(data).expect("failed to read elf"); let is32 = match elf.header.pt2 { HeaderPt2::Header32(_) => true, HeaderPt2::Header64(_) => false, @@ -83,7 +82,7 @@ impl Process { memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack")); let page_table = mc.make_page_table(&memory_set); - debug!("{:#x?}", memory_set); +// debug!("{:#x?}", memory_set); let entry_addr = match elf.header.pt2 { HeaderPt2::Header32(header) => header.entry_point as usize, @@ -97,7 +96,8 @@ impl Process { ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize), ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize), }; - unsafe { memcpy(virt_addr as *mut u8, (begin + offset) as *mut u8, file_size) }; + let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) }; + target.copy_from_slice(&data[offset..offset + file_size]); } if is32 { unsafe { @@ -114,11 +114,11 @@ impl Process { let kstack = mc.alloc_stack(7).unwrap(); let tf = TrapFrame::new_user_thread(entry_addr, user_stack_top, is32); let rsp = kstack.push_at_top(tf); - debug!("rsp = {:#x}", rsp); +// debug!("rsp = {:#x}", rsp); Process { pid: 0, - name: "user", + name: String::new(), kstack, memory_set: Some(memory_set), page_table: Some(page_table), @@ -157,7 +157,7 @@ impl Process { Process { pid: 0, - name: "fork", + name: self.name.clone() + "_fork", kstack, memory_set: Some(memory_set), page_table: Some(page_table), diff --git a/src/process/processor.rs b/src/process/processor.rs index 90cb017..93218fa 100644 --- a/src/process/processor.rs +++ b/src/process/processor.rs @@ -2,17 +2,16 @@ use alloc::BTreeMap; use memory::{ActivePageTable, InactivePageTable}; use super::*; use core::cell::RefCell; +use core::fmt::{Debug, Formatter, Error}; pub struct Processor { - mc: RefCell<MemoryController>, procs: BTreeMap<Pid, Process>, current_pid: Pid, } impl Processor { - pub fn new(mc: MemoryController) -> Self { + pub fn new() -> Self { Processor { - mc: RefCell::new(mc), procs: BTreeMap::<Pid, Process>::new(), current_pid: 0, } @@ -85,12 +84,6 @@ impl Processor { self.get(self.current_pid) } - /// Fork the current process - pub fn fork(&mut self, tf: &TrapFrame) { - let new = self.current().fork(tf, &mut self.mc.borrow_mut()); - self.add(new); - } - pub fn kill(&mut self, pid: Pid) { let process = self.procs.get_mut(&pid).unwrap(); process.status = Status::Exited; @@ -101,4 +94,12 @@ impl Processor { debug!("Processor: {} exit, code: {}", pid, error_code); self.kill(pid); } +} + +impl Debug for Processor { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_map() + .entries(self.procs.iter().map(|(pid, proc0)| { (pid, &proc0.name) })) + .finish() + } } \ No newline at end of file diff --git a/user/hello.o b/user/hello.o deleted file mode 100644 index 4f1d646bdf406431af15f6782e00c2ef1929cd17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40914 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 I@DxS;A1vN`GXMYp