hdr = *sc_vec; /* Place state to the user's signal context space after the hdr */
state = (struct __sc_riscv_v_state __user *)(hdr + 1); /* Point datap right after the end of __sc_riscv_v_state */
datap = state + 1;
/* datap is designed to be 16 byte aligned for better performance */
WARN_ON(!IS_ALIGNED((unsignedlong)datap, 16));
/* Copy everything of vstate but datap. */
err = __copy_to_user(&state->v_state, ¤t->thread.vstate,
offsetof(struct __riscv_v_ext_state, datap)); /* Copy the pointer datap itself. */
err |= __put_user((__force void *)datap, &state->v_state.datap); /* Copy the whole vector content to user space datap. */
err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize); /* Copy magic to the user space after saving all vector conetext */
err |= __put_user(RISCV_V_MAGIC, &hdr->magic);
err |= __put_user(riscv_v_sc_size, &hdr->size); if (unlikely(err)) return err;
/* Only progress the sv_vec if everything has done successfully */
*sc_vec += riscv_v_sc_size; return 0;
}
/* * Restore Vector extension context from the user's signal frame. This function * assumes a valid extension header. So magic and size checking must be done by * the caller.
*/ staticlong __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
{ long err; struct __sc_riscv_v_state __user *state = sc_vec; void __user *datap;
/* * Mark the vstate as clean prior performing the actual copy, * to avoid getting the vstate incorrectly clobbered by the * discarded vector state.
*/
riscv_v_vstate_set_restore(current, regs);
/* Copy everything of __sc_riscv_v_state except datap. */
err = __copy_from_user(¤t->thread.vstate, &state->v_state,
offsetof(struct __riscv_v_ext_state, datap)); if (unlikely(err)) return err;
/* Copy the pointer datap itself. */
err = __get_user(datap, &state->v_state.datap); if (unlikely(err)) return err; /* * Copy the whole vector content from user space datap. Use * copy_from_user to prevent information leak.
*/ return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize);
} #else #define save_v_state(task, regs) (0) #define __restore_v_state(task, regs) (0) #endif
staticlong restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
{ void __user *sc_ext_ptr = &sc->sc_extdesc.hdr;
__u32 rsvd; long err; /* sc_regs is structured the same as the start of pt_regs */
err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); if (unlikely(err)) return err;
/* Restore the floating-point state. */ if (has_fpu()) {
err = restore_fp_state(regs, &sc->sc_fpregs); if (unlikely(err)) return err;
}
/* Check the reserved word before extensions parsing */
err = __get_user(rsvd, &sc->sc_extdesc.reserved); if (unlikely(err)) return err; if (unlikely(rsvd)) return -EINVAL;
/* sc_regs is structured the same as the start of pt_regs */
err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ if (has_fpu())
err |= save_fp_state(regs, &sc->sc_fpregs); /* Save the vector state. */ if ((has_vector() || has_xtheadvector()) && riscv_v_vstate_query(regs))
err |= save_v_state(regs, (void __user **)&sc_ext_ptr); /* Write zero to fp-reserved space and check it on restore_sigcontext */
err |= __put_user(0, &sc->sc_extdesc.reserved); /* And put END __riscv_ctx_hdr at the end. */
err |= __put_user(END_MAGIC, &sc_ext_ptr->magic);
err |= __put_user(END_HDR_SIZE, &sc_ext_ptr->size);
return err;
}
staticinlinevoid __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t framesize)
{ unsignedlong sp; /* Default to using normal stack */
sp = regs->sp;
/* * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV.
*/ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) return (void __user __force *)(-1UL);
/* This is the X/Open sanctioned signal stack switching. */
sp = sigsp(sp, ksig) - framesize;
/* Set up to return from userspace. */ #ifdef CONFIG_MMU
regs->ra = (unsignedlong)VDSO_SYMBOL(
current->mm->context.vdso, rt_sigreturn); #else /* * For the nommu case we don't have a VDSO. Instead we push two * instructions to call the rt_sigreturn syscall onto the user stack.
*/ if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn, sizeof(frame->sigreturn_code))) return -EFAULT;
addr = (unsignedlong)&frame->sigreturn_code; /* Make sure the two instructions are pushed to icache. */
flush_icache_range(addr, addr + sizeof(frame->sigreturn_code));
regs->ra = addr; #endif/* CONFIG_MMU */
/* * Set up registers for signal handler. * Registers that we don't modify keep the value they had from * user-space at the time we took the signal. * We always pass siginfo and mcontext, regardless of SA_SIGINFO, * since some things rely on this (e.g. glibc's debug/segfault.c).
*/
regs->epc = (unsignedlong)ksig->ka.sa.sa_handler;
regs->sp = (unsignedlong)frame;
regs->a0 = ksig->sig; /* a0: signal number */
regs->a1 = (unsignedlong)(&frame->info); /* a1: siginfo pointer */
regs->a2 = (unsignedlong)(&frame->uc); /* a2: ucontext pointer */
/* If we were from a system call, check for system call restarting */ if (syscall) {
continue_addr = regs->epc;
restart_addr = continue_addr - 4;
retval = regs->a0;
/* * Prepare for system call restart. We do this here so that a * debugger will see the already changed PC.
*/ switch (retval) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: case -ERESTART_RESTARTBLOCK:
regs->a0 = regs->orig_a0;
regs->epc = restart_addr; break;
}
}
/* * Get the signal to deliver. When running under ptrace, at this point * the debugger may change all of our registers.
*/ if (get_signal(&ksig)) { /* * Depending on the signal settings, we may need to revert the * decision to restart the system call, but skip this if a * debugger has chosen to restart at a different PC.
*/ if (regs->epc == restart_addr &&
(retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK ||
(retval == -ERESTARTSYS &&
!(ksig.ka.sa.sa_flags & SA_RESTART)))) {
regs->a0 = -EINTR;
regs->epc = continue_addr;
}
/* Actually deliver the signal */
handle_signal(&ksig, regs); return;
}
/* * Handle restarting a different system call. As above, if a debugger * has chosen to restart at a different PC, ignore the restart.
*/ if (syscall && regs->epc == restart_addr && retval == -ERESTART_RESTARTBLOCK)
regs->a7 = __NR_restart_syscall;
/* * If there is no signal to deliver, we just put the saved * sigmask back.
*/
restore_saved_sigmask();
}
void init_rt_signal_env(void); void __init init_rt_signal_env(void)
{
riscv_v_sc_size = sizeof(struct __riscv_ctx_hdr) + sizeof(struct __sc_riscv_v_state) + riscv_v_vsize; /* * Determine the stack space required for guaranteed signal delivery. * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry * in the auxiliary array at process startup.
*/
signal_minsigstksz = get_rt_frame_size(true);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.