Support specification of stack with clone system call and CLONE_STACK flag
This commit is contained in:
@@ -159,10 +159,16 @@ pub struct SyscallStack {
|
||||
pub rip: usize,
|
||||
pub cs: usize,
|
||||
pub rflags: usize,
|
||||
// Will only be present if syscall is called from another ring
|
||||
pub rsp: usize,
|
||||
pub ss: usize,
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub unsafe extern fn clone_ret() {
|
||||
asm!("pop rbp" : : : : "intel", "volatile");
|
||||
asm!("" : : "{rax}"(0) : : "intel", "volatile");
|
||||
asm!("
|
||||
pop rbp
|
||||
xor rax, rax
|
||||
"
|
||||
: : : : "intel", "volatile");
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ pub struct Context {
|
||||
/// User heap
|
||||
pub heap: Option<SharedMemory>,
|
||||
/// User stack
|
||||
pub stack: Option<Memory>,
|
||||
pub stack: Option<SharedMemory>,
|
||||
/// User signal stack
|
||||
pub sigstack: Option<Memory>,
|
||||
/// User Thread local storage
|
||||
|
||||
@@ -75,7 +75,9 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
});
|
||||
}
|
||||
if let Some(ref stack) = context.stack {
|
||||
memory += stack.size();
|
||||
stack.with(|stack| {
|
||||
memory += stack.size();
|
||||
});
|
||||
}
|
||||
if let Some(ref sigstack) = context.sigstack {
|
||||
memory += sigstack.size();
|
||||
|
||||
@@ -93,7 +93,15 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
|
||||
SYS_GETPID => getpid().map(ContextId::into),
|
||||
SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
|
||||
SYS_GETPPID => getppid().map(ContextId::into),
|
||||
SYS_CLONE => clone(b, bp).map(ContextId::into),
|
||||
SYS_CLONE => {
|
||||
let old_rsp = stack.rsp;
|
||||
if b & flag::CLONE_STACK == flag::CLONE_STACK {
|
||||
stack.rsp = c;
|
||||
}
|
||||
let ret = clone(b, bp).map(ContextId::into);
|
||||
stack.rsp = old_rsp;
|
||||
ret
|
||||
},
|
||||
SYS_EXIT => exit((b & 0xFF) << 8),
|
||||
SYS_KILL => kill(ContextId::from(b), c),
|
||||
SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
|
||||
|
||||
@@ -23,7 +23,7 @@ use scheme::FileHandle;
|
||||
use syscall;
|
||||
use syscall::data::{SigAction, Stat};
|
||||
use syscall::error::*;
|
||||
use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND,
|
||||
use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_STACK,
|
||||
PROT_EXEC, PROT_READ, PROT_WRITE, SIG_DFL, SIGCONT, SIGTERM,
|
||||
WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped};
|
||||
use syscall::validate::{validate_slice, validate_slice_mut};
|
||||
@@ -186,22 +186,28 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref stack) = context.stack {
|
||||
let mut new_stack = context::memory::Memory::new(
|
||||
VirtualAddress::new(::USER_TMP_STACK_OFFSET),
|
||||
stack.size(),
|
||||
EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE,
|
||||
false
|
||||
);
|
||||
if let Some(ref stack_shared) = context.stack {
|
||||
if flags & CLONE_STACK == CLONE_STACK {
|
||||
stack_option = Some(stack_shared.clone());
|
||||
} else {
|
||||
stack_shared.with(|stack| {
|
||||
let mut new_stack = context::memory::Memory::new(
|
||||
VirtualAddress::new(::USER_TMP_STACK_OFFSET),
|
||||
stack.size(),
|
||||
EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE,
|
||||
false
|
||||
);
|
||||
|
||||
unsafe {
|
||||
intrinsics::copy(stack.start_address().get() as *const u8,
|
||||
new_stack.start_address().get() as *mut u8,
|
||||
stack.size());
|
||||
unsafe {
|
||||
intrinsics::copy(stack.start_address().get() as *const u8,
|
||||
new_stack.start_address().get() as *mut u8,
|
||||
stack.size());
|
||||
}
|
||||
|
||||
new_stack.remap(stack.flags());
|
||||
stack_option = Some(new_stack.to_shared());
|
||||
});
|
||||
}
|
||||
|
||||
new_stack.remap(stack.flags());
|
||||
stack_option = Some(new_stack);
|
||||
}
|
||||
|
||||
if let Some(ref sigstack) = context.sigstack {
|
||||
@@ -457,9 +463,19 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
}
|
||||
|
||||
// Setup user stack
|
||||
if let Some(mut stack) = stack_option {
|
||||
stack.move_to(VirtualAddress::new(::USER_STACK_OFFSET), &mut new_table, &mut temporary_page);
|
||||
context.stack = Some(stack);
|
||||
if let Some(stack_shared) = stack_option {
|
||||
if flags & CLONE_STACK == CLONE_STACK {
|
||||
let frame = active_table.p4()[::USER_STACK_PML4].pointed_frame().expect("user stack not mapped");
|
||||
let flags = active_table.p4()[::USER_STACK_PML4].flags();
|
||||
active_table.with(&mut new_table, &mut temporary_page, |mapper| {
|
||||
mapper.p4_mut()[::USER_STACK_PML4].set(frame, flags);
|
||||
});
|
||||
} else {
|
||||
stack_shared.with(|stack| {
|
||||
stack.move_to(VirtualAddress::new(::USER_STACK_OFFSET), &mut new_table, &mut temporary_page);
|
||||
});
|
||||
}
|
||||
context.stack = Some(stack_shared);
|
||||
}
|
||||
|
||||
// Setup user sigstack
|
||||
@@ -652,7 +668,7 @@ fn fexec_noreturn(
|
||||
::USER_STACK_SIZE,
|
||||
EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE | EntryFlags::USER_ACCESSIBLE,
|
||||
true
|
||||
));
|
||||
).to_shared());
|
||||
|
||||
// Map stack
|
||||
context.sigstack = Some(context::memory::Memory::new(
|
||||
|
||||
Reference in New Issue
Block a user