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
|
/// This must be done, as no locks can be held on the stack during switch
|
||||||
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;
|
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
/// Page table pointer
|
/// Page table pointer
|
||||||
cr3: usize,
|
cr3: usize,
|
||||||
|
@ -96,5 +96,7 @@ impl Context {
|
||||||
|
|
||||||
// Unset global lock, set inside of kernel
|
// Unset global lock, set inside of kernel
|
||||||
CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
|
CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
|
||||||
|
|
||||||
|
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ pub unsafe extern fn syscall() {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn inner() {
|
unsafe fn inner() {
|
||||||
extern {
|
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;
|
let mut a;
|
||||||
|
@ -13,10 +13,11 @@ pub unsafe extern fn syscall() {
|
||||||
let d;
|
let d;
|
||||||
let e;
|
let e;
|
||||||
let f;
|
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");
|
: : : "intel", "volatile");
|
||||||
|
|
||||||
a = syscall(a, b, c, d, e, f);
|
a = syscall(a, b, c, d, e, f, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
||||||
|
@ -36,3 +37,10 @@ pub unsafe extern fn syscall() {
|
||||||
iretq"
|
iretq"
|
||||||
: : : : "intel", "volatile");
|
: : : : "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) -> ! {
|
pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
|
||||||
// Go to usermode
|
// Go to usermode
|
||||||
asm!("xchg bx, bx
|
asm!("mov ds, ax
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
|
@ -201,7 +200,7 @@ pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
|
||||||
: // No output because it never returns
|
: // No output because it never returns
|
||||||
: "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Stack segment
|
: "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Stack segment
|
||||||
"{rbx}"(sp), // Stack pointer
|
"{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
|
"{rdx}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
|
||||||
"{rsi}"(ip) // IP
|
"{rsi}"(ip) // IP
|
||||||
: // No clobers because it never returns
|
: // No clobers because it never returns
|
||||||
|
|
|
@ -141,13 +141,27 @@ pub unsafe fn switch() {
|
||||||
|
|
||||||
let mut to_ptr = 0 as *mut Context;
|
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();
|
let mut context = context_lock.write();
|
||||||
if ! context.running && ! context.blocked && ! context.exited {
|
if ! context.running && ! context.blocked && ! context.exited {
|
||||||
to_ptr = context.deref_mut() as *mut Context;
|
to_ptr = context.deref_mut() as *mut Context;
|
||||||
break;
|
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 {
|
if to_ptr as usize == 0 {
|
||||||
// TODO: Sleep, wait for interrupt
|
// TODO: Sleep, wait for interrupt
|
||||||
|
@ -159,6 +173,9 @@ pub unsafe fn switch() {
|
||||||
|
|
||||||
(&mut *from_ptr).running = false;
|
(&mut *from_ptr).running = false;
|
||||||
(&mut *to_ptr).running = true;
|
(&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);
|
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
|
||||||
|
|
||||||
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
|
(&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) })
|
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) {
|
match Call::from(a) {
|
||||||
Ok(call) => match call {
|
Ok(call) => match call {
|
||||||
Call::Exit => exit(b),
|
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::Dup => dup(b),
|
||||||
Call::Brk => brk(b),
|
Call::Brk => brk(b),
|
||||||
Call::Iopl => iopl(b),
|
Call::Iopl => iopl(b),
|
||||||
Call::Clone => clone(b),
|
Call::Clone => clone(b, stack),
|
||||||
Call::SchedYield => sched_yield()
|
Call::SchedYield => sched_yield()
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -128,9 +131,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
match inner(a, b, c, d, e, f, stack) {
|
||||||
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) {
|
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(value) => (-(value as isize)) as usize
|
Err(value) => (-(value as isize)) as usize
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
///! Process syscalls
|
///! Process syscalls
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
use core::str;
|
use core::str;
|
||||||
|
|
||||||
use arch;
|
use arch;
|
||||||
|
@ -42,9 +43,52 @@ pub fn brk(address: usize) -> Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone(flags: usize) -> Result<usize> {
|
pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
|
||||||
println!("Clone {:X}", flags);
|
println!("Clone {:X}: {:X}", flags, stack_base);
|
||||||
Ok(0)
|
|
||||||
|
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) -> ! {
|
pub fn exit(status: usize) -> ! {
|
||||||
|
|
Loading…
Reference in a new issue