diff --git a/context/mod.rs b/context/mod.rs index a31d7b4aa1df553c0414c2f68f6b49ab1a33b3a0..4b657da583328afc85af8dd24aababa558306f05 100644 --- a/context/mod.rs +++ b/context/mod.rs @@ -141,11 +141,25 @@ pub unsafe fn switch() { let mut to_ptr = 0 as *mut Context; - for (_pid, context_lock) in contexts().map.iter() { - let mut context = context_lock.write(); - if ! context.running && ! context.blocked && ! context.exited { - to_ptr = context.deref_mut() as *mut Context; - break; + for (pid, context_lock) in contexts().map.iter() { + if *pid > (*from_ptr).id { + let mut context = context_lock.write(); + if ! context.running && ! context.blocked && ! context.exited { + to_ptr = context.deref_mut() as *mut Context; + break; + } + } + } + + if to_ptr as usize == 0 { + for (pid, context_lock) in contexts().map.iter() { + if *pid < (*from_ptr).id { + let mut context = context_lock.write(); + if ! context.running && ! context.blocked && ! context.exited { + to_ptr = context.deref_mut() as *mut Context; + break; + } + } } } @@ -159,6 +173,9 @@ pub unsafe fn switch() { (&mut *from_ptr).running = false; (&mut *to_ptr).running = true; + if let Some(ref stack) = (*to_ptr).kstack { + arch::gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64; + } CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst); (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch); diff --git a/syscall/mod.rs b/syscall/mod.rs index 3fdb7a579f0f9cc9fd6f72a0005ba0bf12a39490..bd53ad479f3dbe283d2145922bf6cbd3555f5771 100644 --- a/syscall/mod.rs +++ b/syscall/mod.rs @@ -105,32 +105,33 @@ pub fn convert_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) } -pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Result<usize> { - match Call::from(a) { - Ok(call) => match call { - Call::Exit => exit(b), - Call::Read => read(b, convert_slice_mut(c as *mut u8, d)?), - Call::Write => write(b, convert_slice(c as *const u8, d)?), - Call::Open => open(convert_slice(b as *const u8, c)?, d), - Call::Close => close(b), - Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), - Call::GetPid => getpid(), - Call::Dup => dup(b), - Call::Brk => brk(b), - Call::Iopl => iopl(b), - Call::Clone => clone(b), - Call::SchedYield => sched_yield() - }, - Err(err) => { - println!("Unknown syscall {}", a); - Err(err) +#[no_mangle] +pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { + #[inline(always)] + fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> { + match Call::from(a) { + Ok(call) => match call { + Call::Exit => exit(b), + Call::Read => read(b, convert_slice_mut(c as *mut u8, d)?), + Call::Write => write(b, convert_slice(c as *const u8, d)?), + Call::Open => open(convert_slice(b as *const u8, c)?, d), + Call::Close => close(b), + Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), + Call::GetPid => getpid(), + Call::Dup => dup(b), + Call::Brk => brk(b), + Call::Iopl => iopl(b), + Call::Clone => clone(b, stack), + Call::SchedYield => sched_yield() + }, + Err(err) => { + println!("Unknown syscall {}", a); + Err(err) + } } } -} -#[no_mangle] -pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize { - match handle(a, b, c, d, e, f) { + match inner(a, b, c, d, e, f, stack) { Ok(value) => value, Err(value) => (-(value as isize)) as usize } diff --git a/syscall/process.rs b/syscall/process.rs index ad1d107ca0f6b11eb927a7395ffd0ed148a3ea68..c4f846ba057e9b6d4ab80304fa0b69624078c835 100644 --- a/syscall/process.rs +++ b/syscall/process.rs @@ -1,5 +1,6 @@ ///! Process syscalls +use core::mem; use core::str; use arch; @@ -42,9 +43,52 @@ pub fn brk(address: usize) -> Result<usize> { } } -pub fn clone(flags: usize) -> Result<usize> { - println!("Clone {:X}", flags); - Ok(0) +pub fn clone(flags: usize, stack_base: usize) -> Result<usize> { + println!("Clone {:X}: {:X}", flags, stack_base); + + let arch; + let mut stack_option = None; + let mut offset = 0; + + // Copy from old process + { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context = context_lock.read(); + arch = context.arch.clone(); + if let Some(ref stack) = context.kstack { + offset = stack_base - stack.as_ptr() as usize - mem::size_of::<usize>(); // Add clone ret + let mut new_stack = stack.clone(); + unsafe { + let func_ptr = new_stack.as_mut_ptr().offset(offset as isize); + *(func_ptr as *mut usize) = arch::interrupt::syscall::clone_ret as usize; + } + stack_option = Some(new_stack); + } + } + + // Set up new process + let pid; + { + let mut contexts = context::contexts_mut(); + let context_lock = contexts.new_context()?; + let mut context = context_lock.write(); + context.arch = arch; + if let Some(stack) = stack_option.take() { + context.arch.set_stack(stack.as_ptr() as usize + offset); + context.kstack = Some(stack); + } + context.blocked = false; + pid = context.id; + } + + println!("Clone {}", pid); + + unsafe { asm!("xchg bx, bx" : : : : "intel", "volatile"); } + + unsafe { context::switch(); } + + Ok(pid) } pub fn exit(status: usize) -> ! {