WIP: userspace signal handling
This commit is contained in:
@@ -29,4 +29,6 @@ pub const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000;
|
||||
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// End offset of the user image, i.e. kernel start
|
||||
// TODO: Make this offset at least PAGE_SIZE less? There are known hardware bugs on some arches,
|
||||
// for example on x86 if instructions execute near the 48-bit canonical address boundary.
|
||||
pub const USER_END_OFFSET: usize = 256 * PML4_SIZE;
|
||||
|
||||
+18
-40
@@ -140,6 +140,7 @@ pub struct Context {
|
||||
/// The effective namespace id
|
||||
pub ens: SchemeNamespace,
|
||||
|
||||
/// Signal handler
|
||||
pub sig: SignalState,
|
||||
|
||||
/// Process umask
|
||||
@@ -191,8 +192,6 @@ pub struct Context {
|
||||
pub name: Cow<'static, str>,
|
||||
/// The open files in the scheme
|
||||
pub files: Arc<RwLock<Vec<Option<FileDescriptor>>>>,
|
||||
/// Signal actions
|
||||
pub actions: Arc<RwLock<Vec<(SigAction, usize)>>>,
|
||||
/// All contexts except kmain will primarily live in userspace, and enter the kernel only when
|
||||
/// interrupts or syscalls occur. This flag is set for all contexts but kmain.
|
||||
pub userspace: bool,
|
||||
@@ -203,25 +202,20 @@ pub struct Context {
|
||||
pub fmap_ret: Option<Frame>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct SignalState {
|
||||
/// Bitset of pending signals.
|
||||
pub pending: u64,
|
||||
/// Bitset of procmasked signals.
|
||||
pub procmask: u64,
|
||||
/// Offset to jump to when a signal is received.
|
||||
pub user_handler: Option<NonZeroUsize>,
|
||||
/// Offset to jump to when a program fault occurs.
|
||||
pub excp_handler: Option<NonZeroUsize>,
|
||||
/// Signal control page, required for signals to work.
|
||||
pub control: Option<RaiiFrame>,
|
||||
/// Offset within the control page of a naturally aligned, semiatomically accessed, u128.
|
||||
pub sigword_off: u16,
|
||||
|
||||
/// A function pointer to the userspace signal handler.
|
||||
pub handler: Option<SignalHandler>,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SignalHandler {
|
||||
pub handler: NonZeroUsize,
|
||||
pub altstack: Option<Altstack>,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Altstack {
|
||||
pub base: NonZeroUsize,
|
||||
pub len: NonZeroUsize,
|
||||
/// Set whenever the kernel is about to have the context jump to its signal trampoline, but the
|
||||
/// context is currently running.
|
||||
pub is_pending: bool,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -238,9 +232,11 @@ impl Context {
|
||||
egid: 0,
|
||||
ens: SchemeNamespace::from(0),
|
||||
sig: SignalState {
|
||||
pending: 0,
|
||||
procmask: !0,
|
||||
handler: None,
|
||||
user_handler: None,
|
||||
excp_handler: None,
|
||||
control: None,
|
||||
sigword_off: 0,
|
||||
is_pending: false,
|
||||
},
|
||||
umask: 0o022,
|
||||
status: Status::HardBlocked { reason: HardBlockedReason::NotYetStarted },
|
||||
@@ -261,7 +257,6 @@ impl Context {
|
||||
addr_space: None,
|
||||
name: Cow::Borrowed(""),
|
||||
files: Arc::new(RwLock::new(Vec::new())),
|
||||
actions: Self::empty_actions(),
|
||||
userspace: false,
|
||||
ptrace_stop: false,
|
||||
fmap_ret: None,
|
||||
@@ -431,16 +426,6 @@ impl Context {
|
||||
|
||||
core::mem::replace(&mut self.addr_space, addr_space)
|
||||
}
|
||||
pub fn empty_actions() -> Arc<RwLock<Vec<(SigAction, usize)>>> {
|
||||
Arc::new(RwLock::new(vec![(
|
||||
SigAction {
|
||||
sa_handler: unsafe { mem::transmute(SIG_DFL) },
|
||||
sa_mask: 0,
|
||||
sa_flags: SigActionFlags::empty(),
|
||||
},
|
||||
0
|
||||
); 128]))
|
||||
}
|
||||
pub fn caller_ctx(&self) -> CallerCtx {
|
||||
CallerCtx {
|
||||
pid: self.id.into(),
|
||||
@@ -473,13 +458,6 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
impl SignalState {
|
||||
pub fn deliverable(&self) -> u64 {
|
||||
const CANT_BLOCK: u64 = (1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1));
|
||||
self.pending & (CANT_BLOCK | !self.procmask)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper struct for borrowing the syscall head or tail buf.
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowedHtBuf {
|
||||
|
||||
+32
-1
@@ -8,7 +8,7 @@ use syscall::{error::*, flag::MapFlags, GrantFlags, MunmapFlags};
|
||||
|
||||
use crate::{
|
||||
arch::paging::PAGE_SIZE, cpu_set::LogicalCpuSet, memory::{
|
||||
deallocate_frame, deallocate_p2frame, get_page_info, init_frame, the_zeroed_frame, AddRefError, Enomem, Frame, PageInfo, RefCount, RefKind
|
||||
deallocate_frame, deallocate_p2frame, get_page_info, init_frame, the_zeroed_frame, AddRefError, Enomem, Frame, PageInfo, RaiiFrame, RefCount, RefKind
|
||||
}, paging::{
|
||||
Page, PageFlags, PageMapper, RmmA, TableKind, VirtualAddress,
|
||||
}, percpu::PercpuBlock, scheme::{self, KernelSchemes}
|
||||
@@ -466,6 +466,37 @@ impl AddrSpaceWrapper {
|
||||
|
||||
Ok(dst_base)
|
||||
}
|
||||
/// Borrows a page from user memory, requiring that the frame be Allocated and read/write. This
|
||||
/// is intended to be used for user-kernel shared memory.
|
||||
pub fn borrow_frame_enforce_rw_allocated(self: &Arc<Self>, page: Page) -> Result<RaiiFrame> {
|
||||
let mut guard = self.acquire_write();
|
||||
|
||||
let (_start_page, info) = guard.grants.contains(page).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
if !info.can_have_flags(MapFlags::PROT_READ | MapFlags::PROT_WRITE) {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
if !matches!(info.provider, Provider::Allocated { .. }) {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
let frame = if let Some((f, fl)) = guard.table.utable.translate(page.start_address()) && fl.has_write() {
|
||||
Frame::containing(f)
|
||||
} else {
|
||||
let (frame, flush, new_guard) = correct_inner(self, guard, page, AccessMode::Write, 0).map_err(|_| Error::new(ENOMEM))?;
|
||||
flush.flush();
|
||||
guard = new_guard;
|
||||
|
||||
frame
|
||||
};
|
||||
|
||||
match get_page_info(frame).expect("missing page info for Allocated grant").add_ref(RefKind::Shared) {
|
||||
Ok(_) => Ok(unsafe { RaiiFrame::new_unchecked(frame) }),
|
||||
Err(AddRefError::RcOverflow) => Err(Error::new(ENOMEM)),
|
||||
Err(AddRefError::SharedToCow) => unreachable!(),
|
||||
Err(AddRefError::CowToShared) => unreachable!("if it was CoW, it was read-only, but in that case we already called correct_inner"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AddrSpace {
|
||||
pub fn current() -> Result<Arc<AddrSpaceWrapper>> {
|
||||
|
||||
@@ -76,7 +76,6 @@ pub fn init() {
|
||||
context.sched_affinity = LogicalCpuSet::empty();
|
||||
context.sched_affinity.atomic_set(crate::cpu_id());
|
||||
context.name = Cow::Borrowed("kmain");
|
||||
context.sig.procmask = 0;
|
||||
|
||||
self::arch::EMPTY_CR3.call_once(|| unsafe { RmmA::table(TableKind::User) });
|
||||
|
||||
|
||||
+6
-185
@@ -17,7 +17,7 @@ use crate::{
|
||||
use super::ContextId;
|
||||
|
||||
pub fn kmain_signal_handler() {
|
||||
if context::context_id() != ContextId::new(1) {
|
||||
/*if context::context_id() != ContextId::new(1) {
|
||||
log::warn!("kmain signal didn't target PID 1, ignoring");
|
||||
return;
|
||||
}
|
||||
@@ -37,194 +37,15 @@ pub fn kmain_signal_handler() {
|
||||
}
|
||||
} else {
|
||||
log::warn!("Spurious kmain signal, bitmask {bits:#0x}.");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// TODO: Move everything but SIGKILL to userspace. SIGCONT and SIGSTOP do not necessarily need to
|
||||
// be done from this current context.
|
||||
pub fn signal_handler() {
|
||||
let (action, sig) = {
|
||||
// FIXME: Can any low-level state become corrupt if a panic occurs here?
|
||||
let context_lock = context::current().expect("context::signal_handler not inside of context");
|
||||
let mut context = context_lock.write();
|
||||
|
||||
// Lowest-numbered signal first.
|
||||
// TODO: randomly?
|
||||
if context.sig.deliverable() == 0 {
|
||||
return;
|
||||
}
|
||||
let bits = context.sig.deliverable();
|
||||
|
||||
// Always prioritize SIGKILL and SIGSTOP, so processes can't simply keep themselves alive
|
||||
// by killing themselves.
|
||||
let selected = if bits & (1 << (SIGKILL - 1)) != 0 {
|
||||
SIGKILL
|
||||
} else if bits & (1 << (SIGSTOP - 1)) != 0 {
|
||||
SIGSTOP
|
||||
} else {
|
||||
bits.trailing_zeros() as usize + 1
|
||||
};
|
||||
|
||||
context.sig.pending &= !(1 << (selected - 1));
|
||||
|
||||
let actions = context.actions.read();
|
||||
(actions[selected - 1].0, selected)
|
||||
};
|
||||
|
||||
let handler = action.sa_handler.map(|ptr| ptr as usize).unwrap_or(0);
|
||||
|
||||
let thumbs_down = ptrace::breakpoint_callback(
|
||||
/*let thumbs_down = ptrace::breakpoint_callback(
|
||||
PTRACE_STOP_SIGNAL,
|
||||
Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler)),
|
||||
)
|
||||
.and_then(|_| ptrace::next_breakpoint().map(|f| f.contains(PTRACE_FLAG_IGNORE)));
|
||||
|
||||
if sig != SIGKILL && thumbs_down.unwrap_or(false) {
|
||||
// If signal can be and was ignored
|
||||
return;
|
||||
}
|
||||
|
||||
if handler == SIG_DFL {
|
||||
match sig {
|
||||
SIGCHLD => {
|
||||
// println!("SIGCHLD");
|
||||
}
|
||||
SIGCONT => {
|
||||
// println!("Continue");
|
||||
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
|
||||
let (pid, pgid, ppid) = {
|
||||
let context_lock = contexts
|
||||
.current()
|
||||
.expect("context::signal_handler not inside of context");
|
||||
let mut context = context_lock.write();
|
||||
context.status = Status::Runnable;
|
||||
(context.id, context.pgid, context.ppid)
|
||||
};
|
||||
|
||||
if let Some(parent_lock) = contexts.get(ppid) {
|
||||
let waitpid = {
|
||||
let parent = parent_lock.write();
|
||||
Arc::clone(&parent.waitpid)
|
||||
};
|
||||
|
||||
waitpid.send(
|
||||
WaitpidKey {
|
||||
pid: Some(pid),
|
||||
pgid: Some(pgid),
|
||||
},
|
||||
(pid, 0xFFFF),
|
||||
);
|
||||
} else {
|
||||
println!("{}: {} not found for continue", pid.get(), ppid.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: SIGSTOP shouldn't be overridable
|
||||
SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => {
|
||||
// println!("Stop {}", sig);
|
||||
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
|
||||
let (pid, pgid, ppid) = {
|
||||
let context_lock = contexts
|
||||
.current()
|
||||
.expect("context::signal_handler not inside of context");
|
||||
let mut context = context_lock.write();
|
||||
context.status = Status::Stopped(sig);
|
||||
(context.id, context.pgid, context.ppid)
|
||||
};
|
||||
|
||||
if let Some(parent_lock) = contexts.get(ppid) {
|
||||
let waitpid = {
|
||||
let parent = parent_lock.write();
|
||||
Arc::clone(&parent.waitpid)
|
||||
};
|
||||
|
||||
waitpid.send(
|
||||
WaitpidKey {
|
||||
pid: Some(pid),
|
||||
pgid: Some(pgid),
|
||||
},
|
||||
(pid, (sig << 8) | 0x7F),
|
||||
);
|
||||
} else {
|
||||
println!("{}: {} not found for stop", pid.get(), ppid.get());
|
||||
}
|
||||
}
|
||||
|
||||
switch();
|
||||
}
|
||||
_ => {
|
||||
// println!("Exit {}", sig);
|
||||
crate::syscall::exit(sig);
|
||||
}
|
||||
}
|
||||
} else if handler == SIG_IGN {
|
||||
// println!("Ignore");
|
||||
} else {
|
||||
// println!("Call {:X}", handler);
|
||||
|
||||
// TODO: Move more of this to userspace
|
||||
let context_lock = context::current()
|
||||
.expect("context::signal_handler not inside of context");
|
||||
let mut context = context_lock.write();
|
||||
|
||||
let Some(handler) = context.sig.handler else {
|
||||
log::debug!("signal ignored since context did not setup sighandler");
|
||||
return;
|
||||
};
|
||||
let Some(regs) = context.regs_mut() else {
|
||||
log::warn!("cannot send signal to context without userspace registers");
|
||||
return;
|
||||
};
|
||||
let mut intregs = IntRegisters::default();
|
||||
regs.save(&mut intregs);
|
||||
|
||||
const STACK_ADJUST: usize = 256;
|
||||
// TODO: 16 bytes alignment is sufficient unless XSAVE is enabled.
|
||||
const STACK_ALIGN: usize = 64;
|
||||
|
||||
let new_sp_unless_altstack = (regs.stack_pointer() - STACK_ADJUST) / STACK_ALIGN * STACK_ALIGN;
|
||||
|
||||
let new_sp = match handler.altstack {
|
||||
Some(altstack) if !(altstack.base.get()..altstack.base.get() + altstack.len.get()).contains(®s.stack_pointer()) => altstack.base.get() + altstack.len.get(),
|
||||
_ => new_sp_unless_altstack,
|
||||
} - size_of::<SignalStack>();
|
||||
|
||||
let old_procmask = context.sig.procmask;
|
||||
|
||||
context.sig.procmask |= action.sa_mask;
|
||||
|
||||
if !action.sa_flags.contains(SigActionFlags::SA_NODEFER) {
|
||||
context.sig.procmask |= 1 << (sig - 1);
|
||||
}
|
||||
|
||||
let Some(regs) = context.regs_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
regs.set_stack_pointer(new_sp);
|
||||
regs.set_instr_pointer(handler.handler.get());
|
||||
|
||||
drop(context);
|
||||
|
||||
let Ok(slice) = UserSlice::wo(new_sp, size_of::<SignalStack>()) else {
|
||||
return;
|
||||
};
|
||||
let stack = SignalStack {
|
||||
intregs,
|
||||
old_procmask,
|
||||
sa_mask: action.sa_mask,
|
||||
sa_flags: action.sa_flags.bits() as u32,
|
||||
sig_num: sig as u32,
|
||||
sa_handler: action.sa_handler.map_or(0, |h| h as usize),
|
||||
};
|
||||
let Ok(()) = slice.copy_from_slice(&stack) else {
|
||||
return;
|
||||
};
|
||||
}
|
||||
.and_then(|_| ptrace::next_breakpoint().map(|f| f.contains(PTRACE_FLAG_IGNORE)));*/
|
||||
}
|
||||
pub fn excp_handler(signal: usize) {
|
||||
}
|
||||
|
||||
@@ -37,13 +37,6 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> Update
|
||||
return UpdateResult::Skip;
|
||||
}
|
||||
|
||||
let signal = context.sig.deliverable() != 0;
|
||||
|
||||
// Unblock when there are pending nonmasked signals.
|
||||
if matches!(context.status, Status::Blocked) && signal {
|
||||
context.unblock_no_ipi();
|
||||
}
|
||||
|
||||
// Wake from sleep
|
||||
if context.status.is_soft_blocked() && context.wake.is_some() {
|
||||
let wake = context.wake.expect("context::switch: wake not set");
|
||||
@@ -57,7 +50,7 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> Update
|
||||
|
||||
// Switch to context if it needs to run
|
||||
if context.status.is_runnable() {
|
||||
UpdateResult::CanSwitch { signal }
|
||||
UpdateResult::CanSwitch { signal: mem::take(&mut context.sig.is_pending) }
|
||||
} else {
|
||||
UpdateResult::Skip
|
||||
}
|
||||
|
||||
+1
-1
@@ -271,7 +271,7 @@ pub fn ksignal(signal: usize) {
|
||||
context.sig.pending |= 1 << (signal - 1);
|
||||
}
|
||||
}
|
||||
crate::context::signal::signal_handler();
|
||||
crate::context::signal::excp_handler(signal);
|
||||
}
|
||||
|
||||
// TODO: Use this macro on aarch64 too.
|
||||
|
||||
@@ -303,6 +303,9 @@ impl RaiiFrame {
|
||||
.map_err(|_| Enomem)
|
||||
.map(|inner| Self { inner })
|
||||
}
|
||||
pub unsafe fn new_unchecked(inner: Frame) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
pub fn get(&self) -> Frame {
|
||||
self.inner
|
||||
}
|
||||
|
||||
+26
-125
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
arch::paging::{Page, RmmA, RmmArch, VirtualAddress},
|
||||
context::{
|
||||
self, context::{Altstack, HardBlockedReason, SignalHandler}, file::{FileDescriptor, InternalFlags}, memory::{handle_notify_files, AddrSpaceWrapper, Grant, PageSpan}, Context, ContextId, Status
|
||||
self, context::{HardBlockedReason, SignalState}, file::{FileDescriptor, InternalFlags}, memory::{handle_notify_files, AddrSpace, AddrSpaceWrapper, Grant, PageSpan}, Context, ContextId, Status
|
||||
},
|
||||
memory::PAGE_SIZE,
|
||||
ptrace,
|
||||
@@ -142,16 +142,7 @@ enum Operation {
|
||||
// TODO: Remove this once openat is implemented, or allow openat-via-dup via e.g. the top-level
|
||||
// directory.
|
||||
OpenViaDup,
|
||||
|
||||
SchedAffinity,
|
||||
Sigactions(Arc<RwLock<Vec<(SigAction, usize)>>>),
|
||||
Sigprocmask,
|
||||
|
||||
// TODO: REMOVE
|
||||
Sigignmask,
|
||||
|
||||
CurrentSigactions,
|
||||
AwaitingSigactionsChange(Arc<RwLock<Vec<(SigAction, usize)>>>),
|
||||
|
||||
MmapMinAddr(Arc<AddrSpaceWrapper>),
|
||||
}
|
||||
@@ -173,12 +164,7 @@ impl Operation {
|
||||
| Self::AddrSpace { .. }
|
||||
| Self::CurrentAddrSpace
|
||||
| Self::CurrentFiletable
|
||||
| Self::Sigactions(_)
|
||||
| Self::CurrentSigactions
|
||||
| Self::AwaitingSigactionsChange(_)
|
||||
| Self::Sighandler
|
||||
| Self::Sigprocmask
|
||||
| Self::Sigignmask
|
||||
)
|
||||
}
|
||||
fn needs_root(&self) -> bool {
|
||||
@@ -300,16 +286,10 @@ impl<const FULL: bool> ProcScheme<FULL> {
|
||||
Some("name") => (Operation::Name, true),
|
||||
Some("session_id") => (Operation::SessionId, true),
|
||||
Some("sighandler") => (Operation::Sighandler, false),
|
||||
Some("sigprocmask") => (Operation::Sigprocmask, false),
|
||||
Some("sigignmask") => (Operation::Sigignmask, false),
|
||||
Some("start") => (Operation::Start, false),
|
||||
Some("uid") => (Operation::Attr(Attr::Uid), true),
|
||||
Some("gid") => (Operation::Attr(Attr::Gid), true),
|
||||
Some("open_via_dup") => (Operation::OpenViaDup, false),
|
||||
Some("sigactions") => {
|
||||
(Operation::Sigactions(Arc::clone(&get_context(pid)?.read().actions)), false)
|
||||
}
|
||||
Some("current-sigactions") => (Operation::CurrentSigactions, false),
|
||||
Some("mmap-min-addr") => (Operation::MmapMinAddr(Arc::clone(
|
||||
get_context(pid)?
|
||||
.read()
|
||||
@@ -654,12 +634,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
Ok(())
|
||||
})?
|
||||
}
|
||||
Operation::AwaitingSigactionsChange(new) => {
|
||||
with_context_mut(handle.info.pid, |context: &mut Context| {
|
||||
context.actions = new;
|
||||
Ok(())
|
||||
})?
|
||||
}
|
||||
Operation::Trace => {
|
||||
ptrace::close_session(handle.info.pid);
|
||||
|
||||
@@ -926,40 +900,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
offset,
|
||||
),
|
||||
|
||||
Operation::Sighandler => {
|
||||
let handler = context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.read().sig.handler;
|
||||
let altstack = handler.and_then(|h| h.altstack);
|
||||
let data = SetSighandlerData {
|
||||
entry: handler.map_or(0, |h| h.handler.get()),
|
||||
altstack_base: altstack.map_or(0, |a| a.base.get()),
|
||||
altstack_len: altstack.map_or(0, |a| a.len.get()),
|
||||
};
|
||||
buf.copy_exactly(&data)?;
|
||||
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
Operation::Sigprocmask => {
|
||||
let procmask = context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.read().sig.procmask;
|
||||
buf.write_u64(procmask)?;
|
||||
Ok(8)
|
||||
}
|
||||
Operation::Sigignmask => {
|
||||
let mut ignmask = 0_u64;
|
||||
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?;
|
||||
let context = context.read();
|
||||
let actions = context.actions.read();
|
||||
for (idx, (action, _)) in actions.iter().enumerate() {
|
||||
if action.sa_handler == unsafe { core::mem::transmute(SIG_IGN) } {
|
||||
ignmask |= 1 << idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.write_u64(ignmask)?;
|
||||
Ok(8)
|
||||
}
|
||||
Operation::Attr(attr) => {
|
||||
let src_buf = match (
|
||||
attr,
|
||||
@@ -1189,42 +1129,35 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
Operation::Sighandler => {
|
||||
let data = unsafe { buf.read_exact::<SetSighandlerData>()? };
|
||||
|
||||
let new_handler = match NonZeroUsize::new(data.entry) {
|
||||
Some(handler) => Some(SignalHandler {
|
||||
handler,
|
||||
altstack: match (NonZeroUsize::new(data.altstack_base), NonZeroUsize::new(data.altstack_len)) {
|
||||
(Some(base), Some(len)) => Some(Altstack { base, len }),
|
||||
_ => None,
|
||||
}
|
||||
}),
|
||||
None => None,
|
||||
if data.user_handler >= crate::USER_END_OFFSET || data.excp_handler >= crate::USER_END_OFFSET {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
let (control, sigword_off) = if data.word_addr != 0 {
|
||||
let offset = u16::try_from(data.word_addr % PAGE_SIZE).unwrap();
|
||||
|
||||
if offset % 16 != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let frame = AddrSpace::current()?
|
||||
.borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.word_addr)))?;
|
||||
|
||||
(Some(frame), offset)
|
||||
} else {
|
||||
(None, 0)
|
||||
};
|
||||
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig.handler = new_handler;
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig = SignalState {
|
||||
user_handler: NonZeroUsize::new(data.user_handler),
|
||||
excp_handler: NonZeroUsize::new(data.excp_handler),
|
||||
control,
|
||||
sigword_off,
|
||||
is_pending: false,
|
||||
};
|
||||
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
Operation::Sigprocmask => {
|
||||
let new_procmask = buf.read_u64()?;
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig.procmask = new_procmask;
|
||||
Ok(8)
|
||||
}
|
||||
// TODO: Remove!
|
||||
Operation::Sigignmask => {
|
||||
let new_ignmask = buf.read_u64()?;
|
||||
let contexts = context::contexts();
|
||||
let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?;
|
||||
let context = context.read();
|
||||
let mut actions = context.actions.write();
|
||||
for bit in (0..64).filter(|bit| new_ignmask & (1 << bit) != 0) {
|
||||
actions[bit] = (SigAction {
|
||||
sa_flags: SigActionFlags::empty(),
|
||||
sa_mask: 0,
|
||||
sa_handler: unsafe { core::mem::transmute(SIG_IGN) },
|
||||
}, 0);
|
||||
}
|
||||
Ok(8)
|
||||
}
|
||||
Operation::Start => match context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().status {
|
||||
ref mut status @ Status::HardBlocked { reason: HardBlockedReason::NotYetStarted } => {
|
||||
*status = Status::Runnable;
|
||||
@@ -1311,28 +1244,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
|
||||
Ok(3 * mem::size_of::<usize>())
|
||||
}
|
||||
Operation::CurrentSigactions => {
|
||||
let sigactions_fd = buf.read_usize()?;
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(sigactions_fd)?;
|
||||
verify_scheme(hopefully_this_scheme)?;
|
||||
|
||||
let mut handles = HANDLES.write();
|
||||
let Operation::Sigactions(ref sigactions) = handles
|
||||
.get(&number)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.info
|
||||
.operation
|
||||
else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
|
||||
handles
|
||||
.get_mut(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.info
|
||||
.operation = Operation::AwaitingSigactionsChange(Arc::clone(sigactions));
|
||||
Ok(mem::size_of::<usize>())
|
||||
}
|
||||
Operation::MmapMinAddr(ref addrspace) => {
|
||||
let val = buf.read_usize()?;
|
||||
if val % PAGE_SIZE != 0 || val > crate::USER_END_OFFSET {
|
||||
@@ -1373,10 +1284,8 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
Operation::Attr(Attr::Gid) => "gid",
|
||||
Operation::Filetable { .. } => "filetable",
|
||||
Operation::AddrSpace { .. } => "addrspace",
|
||||
Operation::Sigactions(_) => "sigactions",
|
||||
Operation::CurrentAddrSpace => "current-addrspace",
|
||||
Operation::CurrentFiletable => "current-filetable",
|
||||
Operation::CurrentSigactions => "current-sigactions",
|
||||
Operation::OpenViaDup => "open-via-dup",
|
||||
Operation::MmapMinAddr(_) => "mmap-min-addr",
|
||||
Operation::SchedAffinity => "sched-affinity",
|
||||
@@ -1523,14 +1432,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
|
||||
handle(operation, OperationData::Offset, true)
|
||||
}
|
||||
Operation::Sigactions(ref sigactions) => {
|
||||
let new = match buf {
|
||||
b"empty" => Context::empty_actions(),
|
||||
b"copy" => Arc::new(RwLock::new(sigactions.read().clone())),
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
handle(Operation::Sigactions(new), OperationData::Other, false)
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
})
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
|
||||
@@ -1546,7 +1447,7 @@ fn inherit_context() -> Result<ContextId> {
|
||||
let current_context_lock = Arc::clone(context::contexts().current().ok_or(Error::new(ESRCH))?);
|
||||
let new_context_lock = Arc::clone(context::contexts_mut().spawn(true, clone_handler)?);
|
||||
|
||||
// (Starts with "all signals blocked".)
|
||||
// (Signals are initially disabled.)
|
||||
|
||||
let current_context = current_context_lock.read();
|
||||
let mut new_context = new_context_lock.write();
|
||||
|
||||
@@ -224,19 +224,6 @@ pub fn syscall(
|
||||
SYS_SETREUID => setreuid(b as u32, c as u32),
|
||||
SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
|
||||
SYS_SETREGID => setregid(b as u32, c as u32),
|
||||
SYS_SIGACTION => sigaction(
|
||||
b,
|
||||
UserSlice::ro(c, core::mem::size_of::<SigAction>())?.none_if_null(),
|
||||
UserSlice::wo(d, core::mem::size_of::<SigAction>())?.none_if_null(),
|
||||
e,
|
||||
)
|
||||
.map(|()| 0),
|
||||
SYS_SIGPROCMASK => sigprocmask(
|
||||
b,
|
||||
UserSlice::ro(c, 8)?.none_if_null(),
|
||||
UserSlice::wo(d, 8)?.none_if_null(),
|
||||
).map(|()| 0),
|
||||
SYS_SIGRETURN => sigreturn().map(|()| 0),
|
||||
SYS_UMASK => umask(b),
|
||||
SYS_VIRTTOPHYS => virttophys(b),
|
||||
|
||||
|
||||
+1
-73
@@ -160,7 +160,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
return true;
|
||||
}
|
||||
|
||||
context.sig.pending |= 1_u64 << (sig - 1);
|
||||
todo!();
|
||||
|
||||
// Convert stopped processes to blocked if sending SIGCONT
|
||||
if sig == SIGCONT {
|
||||
@@ -266,78 +266,6 @@ pub fn setpgid(pid: ContextId, pgid: ContextId) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sigaction(
|
||||
sig: usize,
|
||||
act_opt: Option<UserSliceRo>,
|
||||
oldact_opt: Option<UserSliceWo>,
|
||||
restorer: usize,
|
||||
) -> Result<()> {
|
||||
if sig == 0 || sig > 0x7F {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||
let context = context_lock.read();
|
||||
let mut actions = context.actions.write();
|
||||
|
||||
if let Some(oldact) = oldact_opt {
|
||||
oldact.copy_exactly(&actions[sig - 1].0)?;
|
||||
}
|
||||
|
||||
if let Some(act) = act_opt {
|
||||
actions[sig - 1] = (unsafe { act.read_exact::<SigAction>()? }, restorer);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sigprocmask(how: usize, mask_ref_opt: Option<UserSliceRo>, oldmask_out_opt: Option<UserSliceWo>) -> Result<()> {
|
||||
let mask_opt = mask_ref_opt.map(|m| m.read_u64()).transpose()?;
|
||||
|
||||
let old_sigmask;
|
||||
|
||||
{
|
||||
let context_lock = context::current()?;
|
||||
let mut context = context_lock.write();
|
||||
|
||||
old_sigmask = context.sig.procmask;
|
||||
|
||||
if let Some(arg) = mask_opt {
|
||||
match how {
|
||||
SIG_BLOCK => context.sig.procmask |= arg,
|
||||
SIG_UNBLOCK => context.sig.procmask &= !arg,
|
||||
SIG_SETMASK => context.sig.procmask = arg,
|
||||
_ => {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(oldmask_out) = oldmask_out_opt {
|
||||
oldmask_out.write_u64(old_sigmask)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sigreturn() -> Result<()> {
|
||||
let context = context::current()?;
|
||||
|
||||
let mut stack = SignalStack::default();
|
||||
|
||||
// Kernel-only contexts can't call sigreturn in the first place, so a panic would be
|
||||
// acceptable, but handle it anyway.
|
||||
let stack_ptr = context.read().regs().ok_or(Error::new(EINVAL))?.stack_pointer();
|
||||
|
||||
UserSlice::ro(stack_ptr, mem::size_of::<SignalStack>())?.copy_to_slice(&mut stack)?;
|
||||
|
||||
let mut context = context.write();
|
||||
context.regs_mut().ok_or(Error::new(EINVAL))?.load(&stack.intregs);
|
||||
context.sig.procmask = stack.old_procmask;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn umask(mask: usize) -> Result<usize> {
|
||||
let previous;
|
||||
{
|
||||
|
||||
+1
-1
Submodule syscall updated: ef099bdd2e...16ced74677
Reference in New Issue
Block a user