static void setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct exregs_regs *regs) { struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); unsigned long handler = (unsigned long)ka->sa.sa_handler; int err = 0; printk_dbg("%s called\n", __func__); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto badframe; err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } err |= __put_user(handler, &frame->sig_ip); printk_dbg("%s frame->sig_ip = %lx\n", __func__, handler); if (!err) err = setup_return(regs, ka, &frame->retcode, frame, &frame->lr, &frame->usig, usig); if (err) goto badframe; regs->ip = TASK_SIG_BASE; switch (regs->syscall_action) { case 1: /* Syscall */ regs->ip += ((unsigned long)&__wombat_user_sigentry) & ~PAGE_MASK; break; case 0: /* Fault */ case 2: /* Restart syscall */ regs->ip += ((unsigned long)&__wombat_user_sigentry_restart) & ~PAGE_MASK; break; case 4: /* Interrupt syscall */ regs->ip += ((unsigned long)&__wombat_user_sigentry_int) & ~PAGE_MASK; break; default: BUG(); } set_need_restart(current_thread_info(), regs->ip, regs->sp, regs->flags); printk_dbg("SIG deliver (%s:%d:%lx): sp=%p pc=%p\n", current->comm, current->pid, current_thread_info()->user_tid.raw, frame, (void*)regs->ip); return; badframe: force_sigsegv(usig, current); return; }
asmlinkage int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) { sigset_t saveset, newset; printk_dbg("XXX - %s() called\n", __func__); /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); ARM_put_r0(regs, -ERESTART_RESTARTBLOCK); while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (l4_do_signal(&saveset, regs, 1)) return ARM_r0(regs); } }
asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; int ret; printk_dbg("XXX - %s() called\n", __func__); if (act) { old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; }
static int restore_sigcontext(struct sigcontext *sc) { int err = 0; struct exregs_regs regs; struct restore_sigframe __user *restore; printk_dbg("%s called\n", __func__); /* User registers are saved/restored in user.S (__wombat_user_xxx) */ __get_user_error(regs.sp, &sc->arm_sp, err); __get_user_error(regs.ip, &sc->arm_pc, err); __get_user_error(regs.flags, &sc->arm_cpsr, err); restore = (void*)(regs.sp - sizeof(struct restore_sigframe)); __put_user_error(regs.ip, &restore->ret_ip, err); if (!err) { set_need_restart(current_thread_info(), (unsigned long)TASK_SIG_BASE + (((unsigned long)&__wombat_user_sigrestore) & ~PAGE_MASK), (unsigned long)sc, regs.flags); L4_Stop_Thread(current_thread_info()->user_tid); set_user_ipc_cancelled(current_thread_info()); } return err; }
static inline void * get_sigframe(struct k_sigaction *ka, struct exregs_regs *regs, int framesize) { unsigned long sp = regs->sp; printk_dbg("%s called\n", __func__); /* * This is the X/Open sanctioned signal stack switching. */ if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) sp = current->sas_ss_sp + current->sas_ss_size; /* * ATPCS B01 mandates 8-byte alignment */ return (void *)((sp - framesize) & ~7); }
asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigframe *frame; sigset_t set; printk_dbg("XXX - %s() called\n", __func__); /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* * Since we stacked the signal on a 64-bit boundary, * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */ if (ARM_sp(regs) & 7) goto badframe; frame = (struct sigframe *)ARM_sp(regs); if (verify_area(VERIFY_READ, frame, sizeof (*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(&frame->sc)) goto badframe; return ARM_r0(regs); badframe: force_sig(SIGSEGV, current); return 0; }
/* * atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) { sigset_t saveset; printk_dbg("XXX - %s() called\n", __func__); mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); ARM_put_r0(regs, -ERESTART_RESTARTBLOCK); while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (l4_do_signal(&saveset, regs, 1)) return ARM_r0(regs); } }
void l4_arch_setup_frame(int signr, struct k_sigaction * ka, siginfo_t *info, sigset_t *set, struct exregs_regs *regs) { struct thread_info *thread = current_thread_info(); int usig = signr; /* * translate the signal */ if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) usig = thread->exec_domain->signal_invmap[usig]; printk_dbg("%s %d\n", __func__, usig); if (regs->syscall_action == 2) /* restart syscall */ regs->ip -= 4; /* * Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(usig, ka, info, set, regs); else setup_frame(usig, ka, set, regs); }
/* * subbuf_splice_actor - splice up to one subbuf's worth of data */ static int subbuf_splice_actor(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags, struct lib_ring_buffer *buf) { struct channel *chan = buf->backend.chan; const struct lib_ring_buffer_config *config = &chan->backend.config; unsigned int poff, subbuf_pages, nr_pages; struct page *pages[PIPE_DEF_BUFFERS]; struct partial_page partial[PIPE_DEF_BUFFERS]; struct splice_pipe_desc spd = { .pages = pages, .nr_pages = 0, .partial = partial, #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)) .flags = flags, #endif .ops = &ring_buffer_pipe_buf_ops, .spd_release = lib_ring_buffer_page_release, }; unsigned long consumed_old, roffset; unsigned long bytes_avail; /* * Check that a GET_SUBBUF ioctl has been done before. */ WARN_ON(atomic_long_read(&buf->active_readers) != 1); consumed_old = lib_ring_buffer_get_consumed(config, buf); consumed_old += *ppos; /* * Adjust read len, if longer than what is available. * Max read size is 1 subbuffer due to get_subbuf/put_subbuf for * protection. */ bytes_avail = chan->backend.subbuf_size; WARN_ON(bytes_avail > chan->backend.buf_size); len = min_t(size_t, len, bytes_avail); subbuf_pages = bytes_avail >> PAGE_SHIFT; nr_pages = min_t(unsigned int, subbuf_pages, PIPE_DEF_BUFFERS); roffset = consumed_old & PAGE_MASK; poff = consumed_old & ~PAGE_MASK; printk_dbg(KERN_DEBUG "SPLICE actor len %zu pos %zd write_pos %ld\n", len, (ssize_t)*ppos, lib_ring_buffer_get_offset(config, buf)); for (; spd.nr_pages < nr_pages; spd.nr_pages++) { unsigned int this_len; unsigned long *pfnp, new_pfn; struct page *new_page; void **virt; if (!len) break; printk_dbg(KERN_DEBUG "SPLICE actor loop len %zu roffset %ld\n", len, roffset); /* * We have to replace the page we are moving into the splice * pipe. */ new_page = alloc_pages_node(cpu_to_node(max(buf->backend.cpu, 0)), GFP_KERNEL | __GFP_ZERO, 0); if (!new_page) break; new_pfn = page_to_pfn(new_page); this_len = PAGE_SIZE - poff; pfnp = lib_ring_buffer_read_get_pfn(&buf->backend, roffset, &virt); spd.pages[spd.nr_pages] = pfn_to_page(*pfnp); *pfnp = new_pfn; *virt = page_address(new_page); spd.partial[spd.nr_pages].offset = poff; spd.partial[spd.nr_pages].len = this_len; poff = 0; roffset += PAGE_SIZE; len -= this_len; } if (!spd.nr_pages) return 0; return wrapper_splice_to_pipe(pipe, &spd); } ssize_t lib_ring_buffer_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags, struct lib_ring_buffer *buf) { struct channel *chan = buf->backend.chan; const struct lib_ring_buffer_config *config = &chan->backend.config; ssize_t spliced; int ret; if (config->output != RING_BUFFER_SPLICE) return -EINVAL; /* * We require ppos and length to be page-aligned for performance reasons * (no page copy). Size is known using the ioctl * RING_BUFFER_GET_PADDED_SUBBUF_SIZE, which is page-size padded. * We fail when the ppos or len passed is not page-sized, because splice * is not allowed to copy more than the length passed as parameter (so * the ABI does not let us silently copy more than requested to include * padding). */ if (*ppos != PAGE_ALIGN(*ppos) || len != PAGE_ALIGN(len)) return -EINVAL; ret = 0; spliced = 0; printk_dbg(KERN_DEBUG "SPLICE read len %zu pos %zd\n", len, (ssize_t)*ppos); while (len && !spliced) { ret = subbuf_splice_actor(in, ppos, pipe, len, flags, buf); printk_dbg(KERN_DEBUG "SPLICE read loop ret %d\n", ret); if (ret < 0) break; else if (!ret) { if (flags & SPLICE_F_NONBLOCK) ret = -EAGAIN; break; } *ppos += ret; if (ret > len) len = 0; else len -= ret; spliced += ret; } if (spliced) return spliced; return ret; } EXPORT_SYMBOL_GPL(lib_ring_buffer_splice_read); ssize_t vfs_lib_ring_buffer_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { struct lib_ring_buffer *buf = in->private_data; return lib_ring_buffer_splice_read(in, ppos, pipe, len, flags, buf); } EXPORT_SYMBOL_GPL(vfs_lib_ring_buffer_splice_read);
asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs *regs) { printk_dbg("XXX - %s() called\n", __func__); return do_sigaltstack(uss, uoss, ARM_sp(regs)); }
static void setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct exregs_regs *regs) { struct rt_sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); unsigned long handler = (unsigned long)ka->sa.sa_handler; int err = 0; printk_dbg("%s called\n", __func__); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto badframe; __put_user_error(&frame->info, &frame->pinfo, err); __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ err |= clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ regs, set->sig[0]); err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __put_user(handler, &frame->sig_ip); printk_dbg("%s frame->sig_ip = %lx\n", __func__, handler); if (!err) err = setup_return(regs, ka, &frame->retcode, frame, &frame->lr, &frame->usig, usig); if (!err) { /* * For realtime signals we must also set the second and third * arguments for the signal handler. * -- Peter Maydell <*****@*****.**> 2000-12-06 */ // ARM_put_r1(regs, (unsigned long)frame->pinfo); // ARM_put_r2(regs, (unsigned long)frame->puc); } if (err) goto badframe; regs->ip = TASK_SIG_BASE; switch (regs->syscall_action) { case 1: /* Syscall */ regs->ip += ((unsigned long)&__wombat_user_rt_sigentry) & ~PAGE_MASK; break; case 0: /* Fault */ case 2: /* Restart syscall */ regs->ip += ((unsigned long)&__wombat_user_rt_sigentry_restart) & ~PAGE_MASK; break; case 4: /* Interrupt syscall */ regs->ip += ((unsigned long)&__wombat_user_rt_sigentry_int) & ~PAGE_MASK; break; default: BUG(); } set_need_restart(current_thread_info(), regs->ip, regs->sp, regs->flags); printk_dbg("SIG rt deliver (%s:%d:%lx): sp=%p pc=%p\n", current->comm, current->pid, current_thread_info()->user_tid.raw, frame, (void*)regs->ip); return; badframe: force_sigsegv(usig, current); return; }
static int setup_return(struct exregs_regs *regs, struct k_sigaction *ka, unsigned long __user *rc, void __user *frame, unsigned long __user *lr, int __user *sig, int usig) { unsigned long retcode; int thumb = 0; unsigned long cpsr = regs->flags & ~PSR_f; unsigned long handler = (unsigned long)ka->sa.sa_handler; /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. */ if (ka->sa.sa_flags & SA_THIRTYTWO) cpsr = (cpsr & ~MODE_MASK) | USR_MODE; /* Thumb mode tests */ /* * The LSB of the handler determines if we're going to * be using THUMB or ARM mode for this signal handler. */ thumb = handler & 1; if (thumb) cpsr |= PSR_T_BIT; else cpsr &= ~PSR_T_BIT; if (thumb) { printk("%d: Thumb mode handlers not suppoted\n", current->pid); return 1; } if (ka->sa.sa_flags & SA_RESTORER) { retcode = (unsigned long)ka->sa.sa_restorer; } else { unsigned int idx = thumb << 1; if (ka->sa.sa_flags & SA_SIGINFO) idx += 3; if (__put_user(sigreturn_codes[idx], rc) || __put_user(sigreturn_codes[idx+1], rc+1)) return 1; /* * Ensure that the instruction cache sees * the return code written onto the stack. */ flush_icache_range((unsigned long)rc, (unsigned long)(rc + 1)); retcode = ((unsigned long)rc) + thumb; } if (__put_user(usig, sig)) return 1; if (__put_user(retcode, lr)) return 1; printk_dbg("%s %d restorer = %lx, frame = %p\n", __func__, __LINE__, retcode, frame); regs->sp = (unsigned long)frame; regs->flags = cpsr; // ARM_put_r0(regs, usig); // ARM_put_lr(regs, retcode); return 0; }