mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 02:26:46 +00:00
112 lines
2.7 KiB
Rust
112 lines
2.7 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
use super::SyscallReturn;
|
|
use crate::{
|
|
prelude::*,
|
|
process::signal::{SigStack, SigStackFlags},
|
|
};
|
|
|
|
pub fn sys_sigaltstack(
|
|
sig_stack_addr: Vaddr,
|
|
old_sig_stack_addr: Vaddr,
|
|
ctx: &Context,
|
|
) -> Result<SyscallReturn> {
|
|
debug!(
|
|
"sig_stack_addr = 0x{:x}, old_sig_stack_addr: 0x{:x}",
|
|
sig_stack_addr, old_sig_stack_addr
|
|
);
|
|
|
|
let old_stack = {
|
|
let sig_stack = ctx.posix_thread.sig_stack().lock();
|
|
sig_stack.clone()
|
|
};
|
|
|
|
get_old_stack(old_sig_stack_addr, old_stack.as_ref())?;
|
|
set_new_stack(sig_stack_addr, old_stack.as_ref(), ctx)?;
|
|
|
|
Ok(SyscallReturn::Return(0))
|
|
}
|
|
|
|
fn get_old_stack(old_sig_stack_addr: Vaddr, old_stack: Option<&SigStack>) -> Result<()> {
|
|
if old_sig_stack_addr == 0 {
|
|
return Ok(());
|
|
}
|
|
|
|
let Some(old_stack) = old_stack else {
|
|
return Ok(());
|
|
};
|
|
|
|
debug!("old stack = {:?}", old_stack);
|
|
|
|
let stack = stack_t::from(old_stack.clone());
|
|
CurrentUserSpace::get().write_val(old_sig_stack_addr, &stack)
|
|
}
|
|
|
|
fn set_new_stack(sig_stack_addr: Vaddr, old_stack: Option<&SigStack>, ctx: &Context) -> Result<()> {
|
|
if sig_stack_addr == 0 {
|
|
return Ok(());
|
|
}
|
|
|
|
if let Some(old_stack) = old_stack
|
|
&& old_stack.is_active()
|
|
{
|
|
return_errno_with_message!(Errno::EPERM, "the old stack is active now");
|
|
}
|
|
|
|
let new_stack = {
|
|
let stack = CurrentUserSpace::get().read_val::<stack_t>(sig_stack_addr)?;
|
|
SigStack::try_from(stack)?
|
|
};
|
|
|
|
debug!("new_stack = {:?}", new_stack);
|
|
|
|
*ctx.posix_thread.sig_stack().lock() = Some(new_stack);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
#[derive(Debug, Clone, Copy, Pod)]
|
|
#[repr(C)]
|
|
struct stack_t {
|
|
// Base address of stack
|
|
sp: Vaddr,
|
|
flags: i32,
|
|
// Number of bytes in stack
|
|
size: usize,
|
|
}
|
|
|
|
impl TryFrom<stack_t> for SigStack {
|
|
type Error = Error;
|
|
|
|
fn try_from(stack: stack_t) -> Result<Self> {
|
|
if stack.flags < 0 {
|
|
return_errno_with_message!(Errno::EINVAL, "negative flags");
|
|
}
|
|
|
|
let flags = SigStackFlags::from_bits(stack.flags as u32)
|
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid flags"))?;
|
|
|
|
if stack.size < MINSTKSZ {
|
|
return_errno_with_message!(Errno::ENOMEM, "stack size is less than MINSTKSZ");
|
|
}
|
|
|
|
Ok(Self::new(stack.sp, flags, stack.size))
|
|
}
|
|
}
|
|
|
|
impl From<SigStack> for stack_t {
|
|
fn from(stack: SigStack) -> Self {
|
|
let flags = stack.flags().bits() as i32 | stack.status() as i32;
|
|
Self {
|
|
sp: stack.base(),
|
|
flags,
|
|
size: stack.size(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused)]
|
|
const SIGSTKSZ: usize = 8192;
|
|
const MINSTKSZ: usize = 2048;
|