Can load user programs from sfs.img (hard linked).

master
WangRunji 7 years ago
parent 893658baf8
commit 731d6319e4

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

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

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

@ -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(); }
// 直接进入用户态暂不可用:内核代码用户不可访问

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

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

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

Binary file not shown.
Loading…
Cancel
Save