162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2009 Sunplus Core Technology Co., Ltd. 462306a36Sopenharmony_ci * Chen Liqin <liqin.chen@sunplusct.com> 562306a36Sopenharmony_ci * Lennox Wu <lennox.wu@sunplusct.com> 662306a36Sopenharmony_ci * Copyright (C) 2012 Regents of the University of California 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/compat.h> 1062306a36Sopenharmony_ci#include <linux/signal.h> 1162306a36Sopenharmony_ci#include <linux/uaccess.h> 1262306a36Sopenharmony_ci#include <linux/syscalls.h> 1362306a36Sopenharmony_ci#include <linux/resume_user_mode.h> 1462306a36Sopenharmony_ci#include <linux/linkage.h> 1562306a36Sopenharmony_ci#include <linux/entry-common.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/ucontext.h> 1862306a36Sopenharmony_ci#include <asm/vdso.h> 1962306a36Sopenharmony_ci#include <asm/signal.h> 2062306a36Sopenharmony_ci#include <asm/signal32.h> 2162306a36Sopenharmony_ci#include <asm/switch_to.h> 2262306a36Sopenharmony_ci#include <asm/vector.h> 2362306a36Sopenharmony_ci#include <asm/csr.h> 2462306a36Sopenharmony_ci#include <asm/cacheflush.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciunsigned long signal_minsigstksz __ro_after_init; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciextern u32 __user_rt_sigreturn[2]; 2962306a36Sopenharmony_cistatic size_t riscv_v_sc_size __ro_after_init; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define DEBUG_SIG 0 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct rt_sigframe { 3462306a36Sopenharmony_ci struct siginfo info; 3562306a36Sopenharmony_ci struct ucontext uc; 3662306a36Sopenharmony_ci#ifndef CONFIG_MMU 3762306a36Sopenharmony_ci u32 sigreturn_code[2]; 3862306a36Sopenharmony_ci#endif 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#ifdef CONFIG_FPU 4262306a36Sopenharmony_cistatic long restore_fp_state(struct pt_regs *regs, 4362306a36Sopenharmony_ci union __riscv_fp_state __user *sc_fpregs) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci long err; 4662306a36Sopenharmony_ci struct __riscv_d_ext_state __user *state = &sc_fpregs->d; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); 4962306a36Sopenharmony_ci if (unlikely(err)) 5062306a36Sopenharmony_ci return err; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci fstate_restore(current, regs); 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic long save_fp_state(struct pt_regs *regs, 5762306a36Sopenharmony_ci union __riscv_fp_state __user *sc_fpregs) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci long err; 6062306a36Sopenharmony_ci struct __riscv_d_ext_state __user *state = &sc_fpregs->d; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci fstate_save(current, regs); 6362306a36Sopenharmony_ci err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); 6462306a36Sopenharmony_ci return err; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci#else 6762306a36Sopenharmony_ci#define save_fp_state(task, regs) (0) 6862306a36Sopenharmony_ci#define restore_fp_state(task, regs) (0) 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_RISCV_ISA_V 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic long save_v_state(struct pt_regs *regs, void __user **sc_vec) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct __riscv_ctx_hdr __user *hdr; 7662306a36Sopenharmony_ci struct __sc_riscv_v_state __user *state; 7762306a36Sopenharmony_ci void __user *datap; 7862306a36Sopenharmony_ci long err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci hdr = *sc_vec; 8162306a36Sopenharmony_ci /* Place state to the user's signal context space after the hdr */ 8262306a36Sopenharmony_ci state = (struct __sc_riscv_v_state __user *)(hdr + 1); 8362306a36Sopenharmony_ci /* Point datap right after the end of __sc_riscv_v_state */ 8462306a36Sopenharmony_ci datap = state + 1; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* datap is designed to be 16 byte aligned for better performance */ 8762306a36Sopenharmony_ci WARN_ON(unlikely(!IS_ALIGNED((unsigned long)datap, 16))); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci riscv_v_vstate_save(current, regs); 9062306a36Sopenharmony_ci /* Copy everything of vstate but datap. */ 9162306a36Sopenharmony_ci err = __copy_to_user(&state->v_state, ¤t->thread.vstate, 9262306a36Sopenharmony_ci offsetof(struct __riscv_v_ext_state, datap)); 9362306a36Sopenharmony_ci /* Copy the pointer datap itself. */ 9462306a36Sopenharmony_ci err |= __put_user(datap, &state->v_state.datap); 9562306a36Sopenharmony_ci /* Copy the whole vector content to user space datap. */ 9662306a36Sopenharmony_ci err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize); 9762306a36Sopenharmony_ci /* Copy magic to the user space after saving all vector conetext */ 9862306a36Sopenharmony_ci err |= __put_user(RISCV_V_MAGIC, &hdr->magic); 9962306a36Sopenharmony_ci err |= __put_user(riscv_v_sc_size, &hdr->size); 10062306a36Sopenharmony_ci if (unlikely(err)) 10162306a36Sopenharmony_ci return err; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Only progress the sv_vec if everything has done successfully */ 10462306a36Sopenharmony_ci *sc_vec += riscv_v_sc_size; 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * Restore Vector extension context from the user's signal frame. This function 11062306a36Sopenharmony_ci * assumes a valid extension header. So magic and size checking must be done by 11162306a36Sopenharmony_ci * the caller. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic long __restore_v_state(struct pt_regs *regs, void __user *sc_vec) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci long err; 11662306a36Sopenharmony_ci struct __sc_riscv_v_state __user *state = sc_vec; 11762306a36Sopenharmony_ci void __user *datap; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* Copy everything of __sc_riscv_v_state except datap. */ 12062306a36Sopenharmony_ci err = __copy_from_user(¤t->thread.vstate, &state->v_state, 12162306a36Sopenharmony_ci offsetof(struct __riscv_v_ext_state, datap)); 12262306a36Sopenharmony_ci if (unlikely(err)) 12362306a36Sopenharmony_ci return err; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Copy the pointer datap itself. */ 12662306a36Sopenharmony_ci err = __get_user(datap, &state->v_state.datap); 12762306a36Sopenharmony_ci if (unlikely(err)) 12862306a36Sopenharmony_ci return err; 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Copy the whole vector content from user space datap. Use 13162306a36Sopenharmony_ci * copy_from_user to prevent information leak. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci err = copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize); 13462306a36Sopenharmony_ci if (unlikely(err)) 13562306a36Sopenharmony_ci return err; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci riscv_v_vstate_restore(current, regs); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci#else 14262306a36Sopenharmony_ci#define save_v_state(task, regs) (0) 14362306a36Sopenharmony_ci#define __restore_v_state(task, regs) (0) 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic long restore_sigcontext(struct pt_regs *regs, 14762306a36Sopenharmony_ci struct sigcontext __user *sc) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci void __user *sc_ext_ptr = &sc->sc_extdesc.hdr; 15062306a36Sopenharmony_ci __u32 rsvd; 15162306a36Sopenharmony_ci long err; 15262306a36Sopenharmony_ci /* sc_regs is structured the same as the start of pt_regs */ 15362306a36Sopenharmony_ci err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); 15462306a36Sopenharmony_ci if (unlikely(err)) 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Restore the floating-point state. */ 15862306a36Sopenharmony_ci if (has_fpu()) { 15962306a36Sopenharmony_ci err = restore_fp_state(regs, &sc->sc_fpregs); 16062306a36Sopenharmony_ci if (unlikely(err)) 16162306a36Sopenharmony_ci return err; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Check the reserved word before extensions parsing */ 16562306a36Sopenharmony_ci err = __get_user(rsvd, &sc->sc_extdesc.reserved); 16662306a36Sopenharmony_ci if (unlikely(err)) 16762306a36Sopenharmony_ci return err; 16862306a36Sopenharmony_ci if (unlikely(rsvd)) 16962306a36Sopenharmony_ci return -EINVAL; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci while (!err) { 17262306a36Sopenharmony_ci __u32 magic, size; 17362306a36Sopenharmony_ci struct __riscv_ctx_hdr __user *head = sc_ext_ptr; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci err |= __get_user(magic, &head->magic); 17662306a36Sopenharmony_ci err |= __get_user(size, &head->size); 17762306a36Sopenharmony_ci if (unlikely(err)) 17862306a36Sopenharmony_ci return err; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci sc_ext_ptr += sizeof(*head); 18162306a36Sopenharmony_ci switch (magic) { 18262306a36Sopenharmony_ci case END_MAGIC: 18362306a36Sopenharmony_ci if (size != END_HDR_SIZE) 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci case RISCV_V_MAGIC: 18862306a36Sopenharmony_ci if (!has_vector() || !riscv_v_vstate_query(regs) || 18962306a36Sopenharmony_ci size != riscv_v_sc_size) 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci err = __restore_v_state(regs, sc_ext_ptr); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci default: 19562306a36Sopenharmony_ci return -EINVAL; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci sc_ext_ptr = (void __user *)head + size; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci return err; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic size_t get_rt_frame_size(bool cal_all) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct rt_sigframe __user *frame; 20562306a36Sopenharmony_ci size_t frame_size; 20662306a36Sopenharmony_ci size_t total_context_size = 0; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci frame_size = sizeof(*frame); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (has_vector()) { 21162306a36Sopenharmony_ci if (cal_all || riscv_v_vstate_query(task_pt_regs(current))) 21262306a36Sopenharmony_ci total_context_size += riscv_v_sc_size; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Preserved a __riscv_ctx_hdr for END signal context header if an 21662306a36Sopenharmony_ci * extension uses __riscv_extra_ext_header 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (total_context_size) 21962306a36Sopenharmony_ci total_context_size += sizeof(struct __riscv_ctx_hdr); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci frame_size += total_context_size; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci frame_size = round_up(frame_size, 16); 22462306a36Sopenharmony_ci return frame_size; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciSYSCALL_DEFINE0(rt_sigreturn) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct pt_regs *regs = current_pt_regs(); 23062306a36Sopenharmony_ci struct rt_sigframe __user *frame; 23162306a36Sopenharmony_ci struct task_struct *task; 23262306a36Sopenharmony_ci sigset_t set; 23362306a36Sopenharmony_ci size_t frame_size = get_rt_frame_size(false); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Always make any pending restarted system calls return -EINTR */ 23662306a36Sopenharmony_ci current->restart_block.fn = do_no_restart_syscall; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci frame = (struct rt_sigframe __user *)regs->sp; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!access_ok(frame, frame_size)) 24162306a36Sopenharmony_ci goto badframe; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 24462306a36Sopenharmony_ci goto badframe; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci set_current_blocked(&set); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) 24962306a36Sopenharmony_ci goto badframe; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (restore_altstack(&frame->uc.uc_stack)) 25262306a36Sopenharmony_ci goto badframe; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci regs->cause = -1UL; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return regs->a0; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cibadframe: 25962306a36Sopenharmony_ci task = current; 26062306a36Sopenharmony_ci if (show_unhandled_signals) { 26162306a36Sopenharmony_ci pr_info_ratelimited( 26262306a36Sopenharmony_ci "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n", 26362306a36Sopenharmony_ci task->comm, task_pid_nr(task), __func__, 26462306a36Sopenharmony_ci frame, (void *)regs->epc, (void *)regs->sp); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci force_sig(SIGSEGV); 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic long setup_sigcontext(struct rt_sigframe __user *frame, 27162306a36Sopenharmony_ci struct pt_regs *regs) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct sigcontext __user *sc = &frame->uc.uc_mcontext; 27462306a36Sopenharmony_ci struct __riscv_ctx_hdr __user *sc_ext_ptr = &sc->sc_extdesc.hdr; 27562306a36Sopenharmony_ci long err; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* sc_regs is structured the same as the start of pt_regs */ 27862306a36Sopenharmony_ci err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); 27962306a36Sopenharmony_ci /* Save the floating-point state. */ 28062306a36Sopenharmony_ci if (has_fpu()) 28162306a36Sopenharmony_ci err |= save_fp_state(regs, &sc->sc_fpregs); 28262306a36Sopenharmony_ci /* Save the vector state. */ 28362306a36Sopenharmony_ci if (has_vector() && riscv_v_vstate_query(regs)) 28462306a36Sopenharmony_ci err |= save_v_state(regs, (void __user **)&sc_ext_ptr); 28562306a36Sopenharmony_ci /* Write zero to fp-reserved space and check it on restore_sigcontext */ 28662306a36Sopenharmony_ci err |= __put_user(0, &sc->sc_extdesc.reserved); 28762306a36Sopenharmony_ci /* And put END __riscv_ctx_hdr at the end. */ 28862306a36Sopenharmony_ci err |= __put_user(END_MAGIC, &sc_ext_ptr->magic); 28962306a36Sopenharmony_ci err |= __put_user(END_HDR_SIZE, &sc_ext_ptr->size); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return err; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic inline void __user *get_sigframe(struct ksignal *ksig, 29562306a36Sopenharmony_ci struct pt_regs *regs, size_t framesize) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci unsigned long sp; 29862306a36Sopenharmony_ci /* Default to using normal stack */ 29962306a36Sopenharmony_ci sp = regs->sp; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * If we are on the alternate signal stack and would overflow it, don't. 30362306a36Sopenharmony_ci * Return an always-bogus address instead so we will die with SIGSEGV. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) 30662306a36Sopenharmony_ci return (void __user __force *)(-1UL); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* This is the X/Open sanctioned signal stack switching. */ 30962306a36Sopenharmony_ci sp = sigsp(sp, ksig) - framesize; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Align the stack frame. */ 31262306a36Sopenharmony_ci sp &= ~0xfUL; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return (void __user *)sp; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int setup_rt_frame(struct ksignal *ksig, sigset_t *set, 31862306a36Sopenharmony_ci struct pt_regs *regs) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct rt_sigframe __user *frame; 32162306a36Sopenharmony_ci long err = 0; 32262306a36Sopenharmony_ci unsigned long __maybe_unused addr; 32362306a36Sopenharmony_ci size_t frame_size = get_rt_frame_size(false); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci frame = get_sigframe(ksig, regs, frame_size); 32662306a36Sopenharmony_ci if (!access_ok(frame, frame_size)) 32762306a36Sopenharmony_ci return -EFAULT; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci err |= copy_siginfo_to_user(&frame->info, &ksig->info); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Create the ucontext. */ 33262306a36Sopenharmony_ci err |= __put_user(0, &frame->uc.uc_flags); 33362306a36Sopenharmony_ci err |= __put_user(NULL, &frame->uc.uc_link); 33462306a36Sopenharmony_ci err |= __save_altstack(&frame->uc.uc_stack, regs->sp); 33562306a36Sopenharmony_ci err |= setup_sigcontext(frame, regs); 33662306a36Sopenharmony_ci err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 33762306a36Sopenharmony_ci if (err) 33862306a36Sopenharmony_ci return -EFAULT; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* Set up to return from userspace. */ 34162306a36Sopenharmony_ci#ifdef CONFIG_MMU 34262306a36Sopenharmony_ci regs->ra = (unsigned long)VDSO_SYMBOL( 34362306a36Sopenharmony_ci current->mm->context.vdso, rt_sigreturn); 34462306a36Sopenharmony_ci#else 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * For the nommu case we don't have a VDSO. Instead we push two 34762306a36Sopenharmony_ci * instructions to call the rt_sigreturn syscall onto the user stack. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn, 35062306a36Sopenharmony_ci sizeof(frame->sigreturn_code))) 35162306a36Sopenharmony_ci return -EFAULT; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci addr = (unsigned long)&frame->sigreturn_code; 35462306a36Sopenharmony_ci /* Make sure the two instructions are pushed to icache. */ 35562306a36Sopenharmony_ci flush_icache_range(addr, addr + sizeof(frame->sigreturn_code)); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci regs->ra = addr; 35862306a36Sopenharmony_ci#endif /* CONFIG_MMU */ 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * Set up registers for signal handler. 36262306a36Sopenharmony_ci * Registers that we don't modify keep the value they had from 36362306a36Sopenharmony_ci * user-space at the time we took the signal. 36462306a36Sopenharmony_ci * We always pass siginfo and mcontext, regardless of SA_SIGINFO, 36562306a36Sopenharmony_ci * since some things rely on this (e.g. glibc's debug/segfault.c). 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci regs->epc = (unsigned long)ksig->ka.sa.sa_handler; 36862306a36Sopenharmony_ci regs->sp = (unsigned long)frame; 36962306a36Sopenharmony_ci regs->a0 = ksig->sig; /* a0: signal number */ 37062306a36Sopenharmony_ci regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */ 37162306a36Sopenharmony_ci regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#if DEBUG_SIG 37462306a36Sopenharmony_ci pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n", 37562306a36Sopenharmony_ci current->comm, task_pid_nr(current), ksig->sig, 37662306a36Sopenharmony_ci (void *)regs->epc, (void *)regs->ra, frame); 37762306a36Sopenharmony_ci#endif 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void handle_signal(struct ksignal *ksig, struct pt_regs *regs) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci sigset_t *oldset = sigmask_to_save(); 38562306a36Sopenharmony_ci int ret; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Are we from a system call? */ 38862306a36Sopenharmony_ci if (regs->cause == EXC_SYSCALL) { 38962306a36Sopenharmony_ci /* Avoid additional syscall restarting via ret_from_exception */ 39062306a36Sopenharmony_ci regs->cause = -1UL; 39162306a36Sopenharmony_ci /* If so, check system call restarting.. */ 39262306a36Sopenharmony_ci switch (regs->a0) { 39362306a36Sopenharmony_ci case -ERESTART_RESTARTBLOCK: 39462306a36Sopenharmony_ci case -ERESTARTNOHAND: 39562306a36Sopenharmony_ci regs->a0 = -EINTR; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci case -ERESTARTSYS: 39962306a36Sopenharmony_ci if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { 40062306a36Sopenharmony_ci regs->a0 = -EINTR; 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci fallthrough; 40462306a36Sopenharmony_ci case -ERESTARTNOINTR: 40562306a36Sopenharmony_ci regs->a0 = regs->orig_a0; 40662306a36Sopenharmony_ci regs->epc -= 0x4; 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci rseq_signal_deliver(ksig, regs); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Set up the stack frame */ 41462306a36Sopenharmony_ci if (is_compat_task()) 41562306a36Sopenharmony_ci ret = compat_setup_rt_frame(ksig, oldset, regs); 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci ret = setup_rt_frame(ksig, oldset, regs); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci signal_setup_done(ret, ksig, 0); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_civoid arch_do_signal_or_restart(struct pt_regs *regs) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct ksignal ksig; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (get_signal(&ksig)) { 42762306a36Sopenharmony_ci /* Actually deliver the signal */ 42862306a36Sopenharmony_ci handle_signal(&ksig, regs); 42962306a36Sopenharmony_ci return; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* Did we come from a system call? */ 43362306a36Sopenharmony_ci if (regs->cause == EXC_SYSCALL) { 43462306a36Sopenharmony_ci /* Avoid additional syscall restarting via ret_from_exception */ 43562306a36Sopenharmony_ci regs->cause = -1UL; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Restart the system call - no handlers present */ 43862306a36Sopenharmony_ci switch (regs->a0) { 43962306a36Sopenharmony_ci case -ERESTARTNOHAND: 44062306a36Sopenharmony_ci case -ERESTARTSYS: 44162306a36Sopenharmony_ci case -ERESTARTNOINTR: 44262306a36Sopenharmony_ci regs->a0 = regs->orig_a0; 44362306a36Sopenharmony_ci regs->epc -= 0x4; 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci case -ERESTART_RESTARTBLOCK: 44662306a36Sopenharmony_ci regs->a0 = regs->orig_a0; 44762306a36Sopenharmony_ci regs->a7 = __NR_restart_syscall; 44862306a36Sopenharmony_ci regs->epc -= 0x4; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * If there is no signal to deliver, we just put the saved 45562306a36Sopenharmony_ci * sigmask back. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci restore_saved_sigmask(); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_civoid init_rt_signal_env(void); 46162306a36Sopenharmony_civoid __init init_rt_signal_env(void) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci riscv_v_sc_size = sizeof(struct __riscv_ctx_hdr) + 46462306a36Sopenharmony_ci sizeof(struct __sc_riscv_v_state) + riscv_v_vsize; 46562306a36Sopenharmony_ci /* 46662306a36Sopenharmony_ci * Determine the stack space required for guaranteed signal delivery. 46762306a36Sopenharmony_ci * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry 46862306a36Sopenharmony_ci * in the auxiliary array at process startup. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci signal_minsigstksz = get_rt_frame_size(true); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_SIGFRAME 47462306a36Sopenharmony_cibool sigaltstack_size_valid(size_t ss_size) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci return ss_size > get_rt_frame_size(false); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci#endif /* CONFIG_DYNAMIC_SIGFRAME */ 479