Allow cloning of kernel threads. Userspace breaks potentially due to stack aliasing
This commit is contained in:
parent
4341a2d725
commit
ce50faf7ca
|
@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
|||
/// This must be done, as no locks can be held on the stack during switch
|
||||
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Context {
|
||||
/// Page table pointer
|
||||
cr3: usize,
|
||||
|
@ -96,5 +96,7 @@ impl Context {
|
|||
|
||||
// Unset global lock, set inside of kernel
|
||||
CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
|
||||
|
||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ pub unsafe extern fn syscall() {
|
|||
#[inline(never)]
|
||||
unsafe fn inner() {
|
||||
extern {
|
||||
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
|
||||
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize;
|
||||
}
|
||||
|
||||
let mut a;
|
||||
|
@ -13,10 +13,11 @@ pub unsafe extern fn syscall() {
|
|||
let d;
|
||||
let e;
|
||||
let f;
|
||||
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
|
||||
let stack;
|
||||
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f), "={rbp}"(stack)
|
||||
: : : "intel", "volatile");
|
||||
|
||||
a = syscall(a, b, c, d, e, f);
|
||||
a = syscall(a, b, c, d, e, f, stack);
|
||||
}
|
||||
|
||||
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
||||
|
@ -36,3 +37,10 @@ pub unsafe extern fn syscall() {
|
|||
iretq"
|
||||
: : : : "intel", "volatile");
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub unsafe extern fn clone_ret() -> usize {
|
||||
asm!("pop rbp"
|
||||
: : : : "intel", "volatile");
|
||||
0
|
||||
}
|
||||
|
|
|
@ -187,8 +187,7 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, page_table: usize, stack_start: us
|
|||
|
||||
pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
|
||||
// Go to usermode
|
||||
asm!("xchg bx, bx
|
||||
mov ds, ax
|
||||
asm!("mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
@ -201,7 +200,7 @@ pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
|
|||
: // No output because it never returns
|
||||
: "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Stack segment
|
||||
"{rbx}"(sp), // Stack pointer
|
||||
"{rcx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag
|
||||
"{rcx}"(3 << 12/* | 1 << 9*/), // Flags - Set IOPL and interrupt enable flag
|
||||
"{rdx}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
|
||||
"{rsi}"(ip) // IP
|
||||
: // No clobers because it never returns
|
||||
|
|
|
@ -141,13 +141,27 @@ pub unsafe fn switch() {
|
|||
|
||||
let mut to_ptr = 0 as *mut Context;
|
||||
|
||||
for (_pid, context_lock) in contexts().map.iter() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if to_ptr as usize == 0 {
|
||||
// TODO: Sleep, wait for interrupt
|
||||
|
@ -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);
|
||||
|
|
|
@ -105,7 +105,10 @@ 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> {
|
||||
#[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),
|
||||
|
@ -118,7 +121,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
|
|||
Call::Dup => dup(b),
|
||||
Call::Brk => brk(b),
|
||||
Call::Iopl => iopl(b),
|
||||
Call::Clone => clone(b),
|
||||
Call::Clone => clone(b, stack),
|
||||
Call::SchedYield => sched_yield()
|
||||
},
|
||||
Err(err) => {
|
||||
|
@ -126,11 +129,9 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
|
|||
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
|
||||
}
|
||||
|
|
|
@ -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) -> ! {
|
||||
|
|
Loading…
Reference in a new issue