1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22c020ed8SCatalin Marinas /*
32c020ed8SCatalin Marinas * Based on arch/arm/kernel/signal.c
42c020ed8SCatalin Marinas *
52c020ed8SCatalin Marinas * Copyright (C) 1995-2009 Russell King
62c020ed8SCatalin Marinas * Copyright (C) 2012 ARM Ltd.
72c020ed8SCatalin Marinas */
82c020ed8SCatalin Marinas
994b07c1fSDave Martin #include <linux/cache.h>
10fd92d4a5SAKASHI Takahiro #include <linux/compat.h>
112c020ed8SCatalin Marinas #include <linux/errno.h>
1220987de3SDave Martin #include <linux/kernel.h>
132c020ed8SCatalin Marinas #include <linux/signal.h>
142c020ed8SCatalin Marinas #include <linux/freezer.h>
1547ccb028SDave Martin #include <linux/stddef.h>
162c020ed8SCatalin Marinas #include <linux/uaccess.h>
1733f08261SDave Martin #include <linux/sizes.h>
18bb4891a6SDave Martin #include <linux/string.h>
1903248addSEric W. Biederman #include <linux/resume_user_mode.h>
202c020ed8SCatalin Marinas #include <linux/ratelimit.h>
21cf7de27aSThomas Garnier #include <linux/syscalls.h>
222c020ed8SCatalin Marinas
238d66772eSJames Morse #include <asm/daifflags.h>
242c020ed8SCatalin Marinas #include <asm/debug-monitors.h>
252c020ed8SCatalin Marinas #include <asm/elf.h>
268ada7aabSArnd Bergmann #include <asm/exception.h>
272c020ed8SCatalin Marinas #include <asm/cacheflush.h>
282c020ed8SCatalin Marinas #include <asm/ucontext.h>
292c020ed8SCatalin Marinas #include <asm/unistd.h>
302c020ed8SCatalin Marinas #include <asm/fpsimd.h>
3117c28958SDave Martin #include <asm/ptrace.h>
32e30e8d46SMark Rutland #include <asm/syscall.h>
332c020ed8SCatalin Marinas #include <asm/signal32.h>
34f71016a8SWill Deacon #include <asm/traps.h>
352c020ed8SCatalin Marinas #include <asm/vdso.h>
362c020ed8SCatalin Marinas
372c020ed8SCatalin Marinas /*
382c020ed8SCatalin Marinas * Do a signal return; undo the signal stack. These are aligned to 128-bit.
392c020ed8SCatalin Marinas */
402c020ed8SCatalin Marinas struct rt_sigframe {
412c020ed8SCatalin Marinas struct siginfo info;
422c020ed8SCatalin Marinas struct ucontext uc;
4320987de3SDave Martin };
4420987de3SDave Martin
4520987de3SDave Martin struct frame_record {
46304ef4e8SWill Deacon u64 fp;
47304ef4e8SWill Deacon u64 lr;
482c020ed8SCatalin Marinas };
492c020ed8SCatalin Marinas
5020987de3SDave Martin struct rt_sigframe_user_layout {
5120987de3SDave Martin struct rt_sigframe __user *sigframe;
5220987de3SDave Martin struct frame_record __user *next_frame;
53bb4891a6SDave Martin
54bb4891a6SDave Martin unsigned long size; /* size of allocated sigframe data */
55bb4891a6SDave Martin unsigned long limit; /* largest allowed size */
56bb4891a6SDave Martin
57bb4891a6SDave Martin unsigned long fpsimd_offset;
58bb4891a6SDave Martin unsigned long esr_offset;
598cd969d2SDave Martin unsigned long sve_offset;
6039e54499SMark Brown unsigned long tpidr2_offset;
6139782210SMark Brown unsigned long za_offset;
62ee072cf7SMark Brown unsigned long zt_offset;
6333f08261SDave Martin unsigned long extra_offset;
64bb4891a6SDave Martin unsigned long end_offset;
6520987de3SDave Martin };
6620987de3SDave Martin
6733f08261SDave Martin #define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16)
6833f08261SDave Martin #define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
6933f08261SDave Martin #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
7033f08261SDave Martin
init_user_layout(struct rt_sigframe_user_layout * user)71bb4891a6SDave Martin static void init_user_layout(struct rt_sigframe_user_layout *user)
72bb4891a6SDave Martin {
7333f08261SDave Martin const size_t reserved_size =
7433f08261SDave Martin sizeof(user->sigframe->uc.uc_mcontext.__reserved);
7533f08261SDave Martin
76bb4891a6SDave Martin memset(user, 0, sizeof(*user));
77bb4891a6SDave Martin user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved);
78bb4891a6SDave Martin
7933f08261SDave Martin user->limit = user->size + reserved_size;
8033f08261SDave Martin
8133f08261SDave Martin user->limit -= TERMINATOR_SIZE;
8233f08261SDave Martin user->limit -= EXTRA_CONTEXT_SIZE;
8333f08261SDave Martin /* Reserve space for extension and terminator ^ */
84bb4891a6SDave Martin }
85bb4891a6SDave Martin
sigframe_size(struct rt_sigframe_user_layout const * user)86bb4891a6SDave Martin static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
87bb4891a6SDave Martin {
88bb4891a6SDave Martin return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
89bb4891a6SDave Martin }
90bb4891a6SDave Martin
91bb4322f7SDave Martin /*
9233f08261SDave Martin * Sanity limit on the approximate maximum size of signal frame we'll
9333f08261SDave Martin * try to generate. Stack alignment padding and the frame record are
9433f08261SDave Martin * not taken into account. This limit is not a guarantee and is
9533f08261SDave Martin * NOT ABI.
9633f08261SDave Martin */
977ddcaf78SMark Brown #define SIGFRAME_MAXSZ SZ_256K
9833f08261SDave Martin
__sigframe_alloc(struct rt_sigframe_user_layout * user,unsigned long * offset,size_t size,bool extend)9933f08261SDave Martin static int __sigframe_alloc(struct rt_sigframe_user_layout *user,
10033f08261SDave Martin unsigned long *offset, size_t size, bool extend)
10133f08261SDave Martin {
10233f08261SDave Martin size_t padded_size = round_up(size, 16);
10333f08261SDave Martin
10433f08261SDave Martin if (padded_size > user->limit - user->size &&
10533f08261SDave Martin !user->extra_offset &&
10633f08261SDave Martin extend) {
10733f08261SDave Martin int ret;
10833f08261SDave Martin
10933f08261SDave Martin user->limit += EXTRA_CONTEXT_SIZE;
11033f08261SDave Martin ret = __sigframe_alloc(user, &user->extra_offset,
11133f08261SDave Martin sizeof(struct extra_context), false);
11233f08261SDave Martin if (ret) {
11333f08261SDave Martin user->limit -= EXTRA_CONTEXT_SIZE;
11433f08261SDave Martin return ret;
11533f08261SDave Martin }
11633f08261SDave Martin
11733f08261SDave Martin /* Reserve space for the __reserved[] terminator */
11833f08261SDave Martin user->size += TERMINATOR_SIZE;
11933f08261SDave Martin
12033f08261SDave Martin /*
12133f08261SDave Martin * Allow expansion up to SIGFRAME_MAXSZ, ensuring space for
12233f08261SDave Martin * the terminator:
12333f08261SDave Martin */
12433f08261SDave Martin user->limit = SIGFRAME_MAXSZ - TERMINATOR_SIZE;
12533f08261SDave Martin }
12633f08261SDave Martin
12733f08261SDave Martin /* Still not enough space? Bad luck! */
12833f08261SDave Martin if (padded_size > user->limit - user->size)
12933f08261SDave Martin return -ENOMEM;
13033f08261SDave Martin
13133f08261SDave Martin *offset = user->size;
13233f08261SDave Martin user->size += padded_size;
13333f08261SDave Martin
13433f08261SDave Martin return 0;
13533f08261SDave Martin }
13633f08261SDave Martin
13733f08261SDave Martin /*
138bb4322f7SDave Martin * Allocate space for an optional record of <size> bytes in the user
139bb4322f7SDave Martin * signal frame. The offset from the signal frame base address to the
140bb4322f7SDave Martin * allocated block is assigned to *offset.
141bb4322f7SDave Martin */
sigframe_alloc(struct rt_sigframe_user_layout * user,unsigned long * offset,size_t size)142bb4322f7SDave Martin static int sigframe_alloc(struct rt_sigframe_user_layout *user,
143bb4322f7SDave Martin unsigned long *offset, size_t size)
144bb4322f7SDave Martin {
14533f08261SDave Martin return __sigframe_alloc(user, offset, size, true);
14633f08261SDave Martin }
147bb4322f7SDave Martin
14833f08261SDave Martin /* Allocate the null terminator record and prevent further allocations */
sigframe_alloc_end(struct rt_sigframe_user_layout * user)14933f08261SDave Martin static int sigframe_alloc_end(struct rt_sigframe_user_layout *user)
15033f08261SDave Martin {
15133f08261SDave Martin int ret;
152bb4322f7SDave Martin
15333f08261SDave Martin /* Un-reserve the space reserved for the terminator: */
15433f08261SDave Martin user->limit += TERMINATOR_SIZE;
15533f08261SDave Martin
15633f08261SDave Martin ret = sigframe_alloc(user, &user->end_offset,
15733f08261SDave Martin sizeof(struct _aarch64_ctx));
15833f08261SDave Martin if (ret)
15933f08261SDave Martin return ret;
16033f08261SDave Martin
16133f08261SDave Martin /* Prevent further allocation: */
16233f08261SDave Martin user->limit = user->size;
163bb4322f7SDave Martin return 0;
164bb4322f7SDave Martin }
165bb4322f7SDave Martin
apply_user_offset(struct rt_sigframe_user_layout const * user,unsigned long offset)166bb4891a6SDave Martin static void __user *apply_user_offset(
167bb4891a6SDave Martin struct rt_sigframe_user_layout const *user, unsigned long offset)
168bb4891a6SDave Martin {
169bb4891a6SDave Martin char __user *base = (char __user *)user->sigframe;
170bb4891a6SDave Martin
171bb4891a6SDave Martin return base + offset;
172bb4891a6SDave Martin }
173bb4891a6SDave Martin
1744e4e9304SMark Brown struct user_ctxs {
1754e4e9304SMark Brown struct fpsimd_context __user *fpsimd;
176b57682b3SMark Brown u32 fpsimd_size;
1774e4e9304SMark Brown struct sve_context __user *sve;
178b57682b3SMark Brown u32 sve_size;
1794e4e9304SMark Brown struct tpidr2_context __user *tpidr2;
180b57682b3SMark Brown u32 tpidr2_size;
1814e4e9304SMark Brown struct za_context __user *za;
182b57682b3SMark Brown u32 za_size;
1834e4e9304SMark Brown struct zt_context __user *zt;
184b57682b3SMark Brown u32 zt_size;
1854e4e9304SMark Brown };
1864e4e9304SMark Brown
preserve_fpsimd_context(struct fpsimd_context __user * ctx)1872c020ed8SCatalin Marinas static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
1882c020ed8SCatalin Marinas {
18965896545SDave Martin struct user_fpsimd_state const *fpsimd =
19065896545SDave Martin ¤t->thread.uw.fpsimd_state;
1912c020ed8SCatalin Marinas int err;
1922c020ed8SCatalin Marinas
1932c020ed8SCatalin Marinas /* copy the FP and status/control registers */
1942c020ed8SCatalin Marinas err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
1952c020ed8SCatalin Marinas __put_user_error(fpsimd->fpsr, &ctx->fpsr, err);
1962c020ed8SCatalin Marinas __put_user_error(fpsimd->fpcr, &ctx->fpcr, err);
1972c020ed8SCatalin Marinas
1982c020ed8SCatalin Marinas /* copy the magic/size information */
1992c020ed8SCatalin Marinas __put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err);
2002c020ed8SCatalin Marinas __put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err);
2012c020ed8SCatalin Marinas
2022c020ed8SCatalin Marinas return err ? -EFAULT : 0;
2032c020ed8SCatalin Marinas }
2042c020ed8SCatalin Marinas
restore_fpsimd_context(struct user_ctxs * user)2054e4e9304SMark Brown static int restore_fpsimd_context(struct user_ctxs *user)
2062c020ed8SCatalin Marinas {
2070abdeff5SDave Martin struct user_fpsimd_state fpsimd;
2082c020ed8SCatalin Marinas int err = 0;
2092c020ed8SCatalin Marinas
21092f14518SMark Brown /* check the size information */
211b57682b3SMark Brown if (user->fpsimd_size != sizeof(struct fpsimd_context))
2122c020ed8SCatalin Marinas return -EINVAL;
2132c020ed8SCatalin Marinas
2142c020ed8SCatalin Marinas /* copy the FP and status/control registers */
2154e4e9304SMark Brown err = __copy_from_user(fpsimd.vregs, &(user->fpsimd->vregs),
2162c020ed8SCatalin Marinas sizeof(fpsimd.vregs));
2174e4e9304SMark Brown __get_user_error(fpsimd.fpsr, &(user->fpsimd->fpsr), err);
2184e4e9304SMark Brown __get_user_error(fpsimd.fpcr, &(user->fpsimd->fpcr), err);
2192c020ed8SCatalin Marinas
2208cd969d2SDave Martin clear_thread_flag(TIF_SVE);
221baa85152SMark Brown current->thread.fp_type = FP_STATE_FPSIMD;
2228cd969d2SDave Martin
2232c020ed8SCatalin Marinas /* load the hardware registers from the fpsimd_state structure */
224c51f9269SArd Biesheuvel if (!err)
225c51f9269SArd Biesheuvel fpsimd_update_current_state(&fpsimd);
2262c020ed8SCatalin Marinas
2272c020ed8SCatalin Marinas return err ? -EFAULT : 0;
2282c020ed8SCatalin Marinas }
2292c020ed8SCatalin Marinas
2308cd969d2SDave Martin
2318cd969d2SDave Martin #ifdef CONFIG_ARM64_SVE
2328cd969d2SDave Martin
preserve_sve_context(struct sve_context __user * ctx)2338cd969d2SDave Martin static int preserve_sve_context(struct sve_context __user *ctx)
2348cd969d2SDave Martin {
2358cd969d2SDave Martin int err = 0;
2368cd969d2SDave Martin u16 reserved[ARRAY_SIZE(ctx->__reserved)];
23785ed24daSMark Brown u16 flags = 0;
2380423eedcSMark Brown unsigned int vl = task_get_sve_vl(current);
2398cd969d2SDave Martin unsigned int vq = 0;
2408cd969d2SDave Martin
24185ed24daSMark Brown if (thread_sm_enabled(¤t->thread)) {
24285ed24daSMark Brown vl = task_get_sme_vl(current);
2438cd969d2SDave Martin vq = sve_vq_from_vl(vl);
24485ed24daSMark Brown flags |= SVE_SIG_FLAG_SM;
245*60480c6bSMark Brown } else if (current->thread.fp_type == FP_STATE_SVE) {
24685ed24daSMark Brown vq = sve_vq_from_vl(vl);
24785ed24daSMark Brown }
2488cd969d2SDave Martin
2498cd969d2SDave Martin memset(reserved, 0, sizeof(reserved));
2508cd969d2SDave Martin
2518cd969d2SDave Martin __put_user_error(SVE_MAGIC, &ctx->head.magic, err);
2528cd969d2SDave Martin __put_user_error(round_up(SVE_SIG_CONTEXT_SIZE(vq), 16),
2538cd969d2SDave Martin &ctx->head.size, err);
2548cd969d2SDave Martin __put_user_error(vl, &ctx->vl, err);
25585ed24daSMark Brown __put_user_error(flags, &ctx->flags, err);
2568cd969d2SDave Martin BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
2578cd969d2SDave Martin err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
2588cd969d2SDave Martin
2598cd969d2SDave Martin if (vq) {
2608cd969d2SDave Martin /*
2618cd969d2SDave Martin * This assumes that the SVE state has already been saved to
26268a4c52eSJulien Grall * the task struct by calling the function
26368a4c52eSJulien Grall * fpsimd_signal_preserve_current_state().
2648cd969d2SDave Martin */
2658cd969d2SDave Martin err |= __copy_to_user((char __user *)ctx + SVE_SIG_REGS_OFFSET,
2668cd969d2SDave Martin current->thread.sve_state,
2678cd969d2SDave Martin SVE_SIG_REGS_SIZE(vq));
2688cd969d2SDave Martin }
2698cd969d2SDave Martin
2708cd969d2SDave Martin return err ? -EFAULT : 0;
2718cd969d2SDave Martin }
2728cd969d2SDave Martin
restore_sve_fpsimd_context(struct user_ctxs * user)2738cd969d2SDave Martin static int restore_sve_fpsimd_context(struct user_ctxs *user)
2748cd969d2SDave Martin {
275f3ac48aaSMark Brown int err = 0;
27685ed24daSMark Brown unsigned int vl, vq;
2770abdeff5SDave Martin struct user_fpsimd_state fpsimd;
278f3ac48aaSMark Brown u16 user_vl, flags;
2798cd969d2SDave Martin
280b57682b3SMark Brown if (user->sve_size < sizeof(*user->sve))
281b57682b3SMark Brown return -EINVAL;
2828cd969d2SDave Martin
283f3ac48aaSMark Brown __get_user_error(user_vl, &(user->sve->vl), err);
284f3ac48aaSMark Brown __get_user_error(flags, &(user->sve->flags), err);
285f3ac48aaSMark Brown if (err)
286f3ac48aaSMark Brown return err;
2878cd969d2SDave Martin
288f3ac48aaSMark Brown if (flags & SVE_SIG_FLAG_SM) {
28985ed24daSMark Brown if (!system_supports_sme())
29085ed24daSMark Brown return -EINVAL;
29185ed24daSMark Brown
29285ed24daSMark Brown vl = task_get_sme_vl(current);
29385ed24daSMark Brown } else {
2947dde62f0SMark Brown /*
2957dde62f0SMark Brown * A SME only system use SVE for streaming mode so can
2967dde62f0SMark Brown * have a SVE formatted context with a zero VL and no
2977dde62f0SMark Brown * payload data.
2987dde62f0SMark Brown */
2997dde62f0SMark Brown if (!system_supports_sve() && !system_supports_sme())
300df07443fSMark Brown return -EINVAL;
301df07443fSMark Brown
30285ed24daSMark Brown vl = task_get_sve_vl(current);
30385ed24daSMark Brown }
30485ed24daSMark Brown
305f3ac48aaSMark Brown if (user_vl != vl)
3068cd969d2SDave Martin return -EINVAL;
3078cd969d2SDave Martin
308b57682b3SMark Brown if (user->sve_size == sizeof(*user->sve)) {
3098cd969d2SDave Martin clear_thread_flag(TIF_SVE);
310ec0067a6SMark Brown current->thread.svcr &= ~SVCR_SM_MASK;
311baa85152SMark Brown current->thread.fp_type = FP_STATE_FPSIMD;
3128cd969d2SDave Martin goto fpsimd_only;
3138cd969d2SDave Martin }
3148cd969d2SDave Martin
315f3ac48aaSMark Brown vq = sve_vq_from_vl(vl);
3168cd969d2SDave Martin
317b57682b3SMark Brown if (user->sve_size < SVE_SIG_CONTEXT_SIZE(vq))
3188cd969d2SDave Martin return -EINVAL;
3198cd969d2SDave Martin
3208cd969d2SDave Martin /*
3218cd969d2SDave Martin * Careful: we are about __copy_from_user() directly into
3228cd969d2SDave Martin * thread.sve_state with preemption enabled, so protection is
3238cd969d2SDave Martin * needed to prevent a racing context switch from writing stale
3248cd969d2SDave Martin * registers back over the new data.
3258cd969d2SDave Martin */
3268cd969d2SDave Martin
3278cd969d2SDave Martin fpsimd_flush_task_state(current);
3288cd969d2SDave Martin /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
3298cd969d2SDave Martin
330826a4fddSMark Brown sve_alloc(current, true);
3317559b7d7SMark Brown if (!current->thread.sve_state) {
3327559b7d7SMark Brown clear_thread_flag(TIF_SVE);
3337559b7d7SMark Brown return -ENOMEM;
3347559b7d7SMark Brown }
3357559b7d7SMark Brown
3368cd969d2SDave Martin err = __copy_from_user(current->thread.sve_state,
3378cd969d2SDave Martin (char __user const *)user->sve +
3388cd969d2SDave Martin SVE_SIG_REGS_OFFSET,
3398cd969d2SDave Martin SVE_SIG_REGS_SIZE(vq));
3408cd969d2SDave Martin if (err)
3418cd969d2SDave Martin return -EFAULT;
3428cd969d2SDave Martin
343f3ac48aaSMark Brown if (flags & SVE_SIG_FLAG_SM)
344ec0067a6SMark Brown current->thread.svcr |= SVCR_SM_MASK;
34585ed24daSMark Brown else
3468cd969d2SDave Martin set_thread_flag(TIF_SVE);
347baa85152SMark Brown current->thread.fp_type = FP_STATE_SVE;
3488cd969d2SDave Martin
3498cd969d2SDave Martin fpsimd_only:
3508cd969d2SDave Martin /* copy the FP and status/control registers */
3518cd969d2SDave Martin /* restore_sigframe() already checked that user->fpsimd != NULL. */
3528cd969d2SDave Martin err = __copy_from_user(fpsimd.vregs, user->fpsimd->vregs,
3538cd969d2SDave Martin sizeof(fpsimd.vregs));
3548cd969d2SDave Martin __get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err);
3558cd969d2SDave Martin __get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err);
3568cd969d2SDave Martin
3578cd969d2SDave Martin /* load the hardware registers from the fpsimd_state structure */
3588cd969d2SDave Martin if (!err)
3598cd969d2SDave Martin fpsimd_update_current_state(&fpsimd);
3608cd969d2SDave Martin
3618cd969d2SDave Martin return err ? -EFAULT : 0;
3628cd969d2SDave Martin }
3638cd969d2SDave Martin
3648cd969d2SDave Martin #else /* ! CONFIG_ARM64_SVE */
3658cd969d2SDave Martin
restore_sve_fpsimd_context(struct user_ctxs * user)366df07443fSMark Brown static int restore_sve_fpsimd_context(struct user_ctxs *user)
367df07443fSMark Brown {
368df07443fSMark Brown WARN_ON_ONCE(1);
369df07443fSMark Brown return -EINVAL;
370df07443fSMark Brown }
371df07443fSMark Brown
372df07443fSMark Brown /* Turn any non-optimised out attempts to use this into a link error: */
3738cd969d2SDave Martin extern int preserve_sve_context(void __user *ctx);
3748cd969d2SDave Martin
3758cd969d2SDave Martin #endif /* ! CONFIG_ARM64_SVE */
3768cd969d2SDave Martin
37739782210SMark Brown #ifdef CONFIG_ARM64_SME
37839782210SMark Brown
preserve_tpidr2_context(struct tpidr2_context __user * ctx)37939e54499SMark Brown static int preserve_tpidr2_context(struct tpidr2_context __user *ctx)
38039e54499SMark Brown {
38139e54499SMark Brown int err = 0;
38239e54499SMark Brown
38339e54499SMark Brown current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
38439e54499SMark Brown
38539e54499SMark Brown __put_user_error(TPIDR2_MAGIC, &ctx->head.magic, err);
38639e54499SMark Brown __put_user_error(sizeof(*ctx), &ctx->head.size, err);
38739e54499SMark Brown __put_user_error(current->thread.tpidr2_el0, &ctx->tpidr2, err);
38839e54499SMark Brown
38939e54499SMark Brown return err;
39039e54499SMark Brown }
39139e54499SMark Brown
restore_tpidr2_context(struct user_ctxs * user)39239e54499SMark Brown static int restore_tpidr2_context(struct user_ctxs *user)
39339e54499SMark Brown {
39439e54499SMark Brown u64 tpidr2_el0;
39539e54499SMark Brown int err = 0;
39639e54499SMark Brown
397b57682b3SMark Brown if (user->tpidr2_size != sizeof(*user->tpidr2))
398b57682b3SMark Brown return -EINVAL;
399b57682b3SMark Brown
40039e54499SMark Brown __get_user_error(tpidr2_el0, &user->tpidr2->tpidr2, err);
40139e54499SMark Brown if (!err)
402616cb2f4SMark Brown write_sysreg_s(tpidr2_el0, SYS_TPIDR2_EL0);
40339e54499SMark Brown
40439e54499SMark Brown return err;
40539e54499SMark Brown }
40639e54499SMark Brown
preserve_za_context(struct za_context __user * ctx)40739782210SMark Brown static int preserve_za_context(struct za_context __user *ctx)
40839782210SMark Brown {
40939782210SMark Brown int err = 0;
41039782210SMark Brown u16 reserved[ARRAY_SIZE(ctx->__reserved)];
41139782210SMark Brown unsigned int vl = task_get_sme_vl(current);
41239782210SMark Brown unsigned int vq;
41339782210SMark Brown
41439782210SMark Brown if (thread_za_enabled(¤t->thread))
41539782210SMark Brown vq = sve_vq_from_vl(vl);
41639782210SMark Brown else
41739782210SMark Brown vq = 0;
41839782210SMark Brown
41939782210SMark Brown memset(reserved, 0, sizeof(reserved));
42039782210SMark Brown
42139782210SMark Brown __put_user_error(ZA_MAGIC, &ctx->head.magic, err);
42239782210SMark Brown __put_user_error(round_up(ZA_SIG_CONTEXT_SIZE(vq), 16),
42339782210SMark Brown &ctx->head.size, err);
42439782210SMark Brown __put_user_error(vl, &ctx->vl, err);
42539782210SMark Brown BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
42639782210SMark Brown err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
42739782210SMark Brown
42839782210SMark Brown if (vq) {
42939782210SMark Brown /*
43039782210SMark Brown * This assumes that the ZA state has already been saved to
43139782210SMark Brown * the task struct by calling the function
43239782210SMark Brown * fpsimd_signal_preserve_current_state().
43339782210SMark Brown */
43439782210SMark Brown err |= __copy_to_user((char __user *)ctx + ZA_SIG_REGS_OFFSET,
435ce514000SMark Brown current->thread.sme_state,
43639782210SMark Brown ZA_SIG_REGS_SIZE(vq));
43739782210SMark Brown }
43839782210SMark Brown
43939782210SMark Brown return err ? -EFAULT : 0;
44039782210SMark Brown }
44139782210SMark Brown
restore_za_context(struct user_ctxs * user)4421bec877bSCatalin Marinas static int restore_za_context(struct user_ctxs *user)
44339782210SMark Brown {
44424d68345SMark Brown int err = 0;
44539782210SMark Brown unsigned int vq;
44624d68345SMark Brown u16 user_vl;
44739782210SMark Brown
448b57682b3SMark Brown if (user->za_size < sizeof(*user->za))
44939782210SMark Brown return -EINVAL;
45039782210SMark Brown
45124d68345SMark Brown __get_user_error(user_vl, &(user->za->vl), err);
45224d68345SMark Brown if (err)
45324d68345SMark Brown return err;
45439782210SMark Brown
45524d68345SMark Brown if (user_vl != task_get_sme_vl(current))
45639782210SMark Brown return -EINVAL;
45739782210SMark Brown
458b57682b3SMark Brown if (user->za_size == sizeof(*user->za)) {
459ec0067a6SMark Brown current->thread.svcr &= ~SVCR_ZA_MASK;
46039782210SMark Brown return 0;
46139782210SMark Brown }
46239782210SMark Brown
46324d68345SMark Brown vq = sve_vq_from_vl(user_vl);
46439782210SMark Brown
465b57682b3SMark Brown if (user->za_size < ZA_SIG_CONTEXT_SIZE(vq))
46639782210SMark Brown return -EINVAL;
46739782210SMark Brown
46839782210SMark Brown /*
46939782210SMark Brown * Careful: we are about __copy_from_user() directly into
470ce514000SMark Brown * thread.sme_state with preemption enabled, so protection is
47139782210SMark Brown * needed to prevent a racing context switch from writing stale
47239782210SMark Brown * registers back over the new data.
47339782210SMark Brown */
47439782210SMark Brown
47539782210SMark Brown fpsimd_flush_task_state(current);
47639782210SMark Brown /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
47739782210SMark Brown
4785d0a8d2fSMark Brown sme_alloc(current, true);
479ce514000SMark Brown if (!current->thread.sme_state) {
480ec0067a6SMark Brown current->thread.svcr &= ~SVCR_ZA_MASK;
48139782210SMark Brown clear_thread_flag(TIF_SME);
48239782210SMark Brown return -ENOMEM;
48339782210SMark Brown }
48439782210SMark Brown
485ce514000SMark Brown err = __copy_from_user(current->thread.sme_state,
48639782210SMark Brown (char __user const *)user->za +
48739782210SMark Brown ZA_SIG_REGS_OFFSET,
48839782210SMark Brown ZA_SIG_REGS_SIZE(vq));
48939782210SMark Brown if (err)
49039782210SMark Brown return -EFAULT;
49139782210SMark Brown
49239782210SMark Brown set_thread_flag(TIF_SME);
493ec0067a6SMark Brown current->thread.svcr |= SVCR_ZA_MASK;
49439782210SMark Brown
49539782210SMark Brown return 0;
49639782210SMark Brown }
497ee072cf7SMark Brown
preserve_zt_context(struct zt_context __user * ctx)498ee072cf7SMark Brown static int preserve_zt_context(struct zt_context __user *ctx)
499ee072cf7SMark Brown {
500ee072cf7SMark Brown int err = 0;
501ee072cf7SMark Brown u16 reserved[ARRAY_SIZE(ctx->__reserved)];
502ee072cf7SMark Brown
503ee072cf7SMark Brown if (WARN_ON(!thread_za_enabled(¤t->thread)))
504ee072cf7SMark Brown return -EINVAL;
505ee072cf7SMark Brown
506ee072cf7SMark Brown memset(reserved, 0, sizeof(reserved));
507ee072cf7SMark Brown
508ee072cf7SMark Brown __put_user_error(ZT_MAGIC, &ctx->head.magic, err);
509ee072cf7SMark Brown __put_user_error(round_up(ZT_SIG_CONTEXT_SIZE(1), 16),
510ee072cf7SMark Brown &ctx->head.size, err);
511ee072cf7SMark Brown __put_user_error(1, &ctx->nregs, err);
512ee072cf7SMark Brown BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
513ee072cf7SMark Brown err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
514ee072cf7SMark Brown
515ee072cf7SMark Brown /*
516ee072cf7SMark Brown * This assumes that the ZT state has already been saved to
517ee072cf7SMark Brown * the task struct by calling the function
518ee072cf7SMark Brown * fpsimd_signal_preserve_current_state().
519ee072cf7SMark Brown */
520ee072cf7SMark Brown err |= __copy_to_user((char __user *)ctx + ZT_SIG_REGS_OFFSET,
521ee072cf7SMark Brown thread_zt_state(¤t->thread),
522ee072cf7SMark Brown ZT_SIG_REGS_SIZE(1));
523ee072cf7SMark Brown
524ee072cf7SMark Brown return err ? -EFAULT : 0;
525ee072cf7SMark Brown }
526ee072cf7SMark Brown
restore_zt_context(struct user_ctxs * user)527ee072cf7SMark Brown static int restore_zt_context(struct user_ctxs *user)
528ee072cf7SMark Brown {
529ee072cf7SMark Brown int err;
530ad678be4SMark Brown u16 nregs;
531ee072cf7SMark Brown
532ee072cf7SMark Brown /* ZA must be restored first for this check to be valid */
533ee072cf7SMark Brown if (!thread_za_enabled(¤t->thread))
534ee072cf7SMark Brown return -EINVAL;
535ee072cf7SMark Brown
536b57682b3SMark Brown if (user->zt_size != ZT_SIG_CONTEXT_SIZE(1))
537b57682b3SMark Brown return -EINVAL;
538b57682b3SMark Brown
539ad678be4SMark Brown if (__copy_from_user(&nregs, &(user->zt->nregs), sizeof(nregs)))
540ee072cf7SMark Brown return -EFAULT;
541ee072cf7SMark Brown
542ad678be4SMark Brown if (nregs != 1)
543ee072cf7SMark Brown return -EINVAL;
544ee072cf7SMark Brown
545ee072cf7SMark Brown /*
546ee072cf7SMark Brown * Careful: we are about __copy_from_user() directly into
547ee072cf7SMark Brown * thread.zt_state with preemption enabled, so protection is
548ee072cf7SMark Brown * needed to prevent a racing context switch from writing stale
549ee072cf7SMark Brown * registers back over the new data.
550ee072cf7SMark Brown */
551ee072cf7SMark Brown
552ee072cf7SMark Brown fpsimd_flush_task_state(current);
553ee072cf7SMark Brown /* From now, fpsimd_thread_switch() won't touch ZT in thread state */
554ee072cf7SMark Brown
555ee072cf7SMark Brown err = __copy_from_user(thread_zt_state(¤t->thread),
556ee072cf7SMark Brown (char __user const *)user->zt +
557ee072cf7SMark Brown ZT_SIG_REGS_OFFSET,
558ee072cf7SMark Brown ZT_SIG_REGS_SIZE(1));
559ee072cf7SMark Brown if (err)
560ee072cf7SMark Brown return -EFAULT;
561ee072cf7SMark Brown
562ee072cf7SMark Brown return 0;
563ee072cf7SMark Brown }
564ee072cf7SMark Brown
56539782210SMark Brown #else /* ! CONFIG_ARM64_SME */
56639782210SMark Brown
56739782210SMark Brown /* Turn any non-optimised out attempts to use these into a link error: */
56839e54499SMark Brown extern int preserve_tpidr2_context(void __user *ctx);
56939e54499SMark Brown extern int restore_tpidr2_context(struct user_ctxs *user);
57039782210SMark Brown extern int preserve_za_context(void __user *ctx);
57139782210SMark Brown extern int restore_za_context(struct user_ctxs *user);
572ee072cf7SMark Brown extern int preserve_zt_context(void __user *ctx);
573ee072cf7SMark Brown extern int restore_zt_context(struct user_ctxs *user);
57439782210SMark Brown
57539782210SMark Brown #endif /* ! CONFIG_ARM64_SME */
5768cd969d2SDave Martin
parse_user_sigframe(struct user_ctxs * user,struct rt_sigframe __user * sf)57747ccb028SDave Martin static int parse_user_sigframe(struct user_ctxs *user,
57847ccb028SDave Martin struct rt_sigframe __user *sf)
57947ccb028SDave Martin {
58047ccb028SDave Martin struct sigcontext __user *const sc = &sf->uc.uc_mcontext;
581bb4891a6SDave Martin struct _aarch64_ctx __user *head;
582bb4891a6SDave Martin char __user *base = (char __user *)&sc->__reserved;
58347ccb028SDave Martin size_t offset = 0;
584bb4891a6SDave Martin size_t limit = sizeof(sc->__reserved);
58533f08261SDave Martin bool have_extra_context = false;
58633f08261SDave Martin char const __user *const sfp = (char const __user *)sf;
58747ccb028SDave Martin
58847ccb028SDave Martin user->fpsimd = NULL;
5898cd969d2SDave Martin user->sve = NULL;
59039e54499SMark Brown user->tpidr2 = NULL;
59139782210SMark Brown user->za = NULL;
592ee072cf7SMark Brown user->zt = NULL;
59347ccb028SDave Martin
594bb4891a6SDave Martin if (!IS_ALIGNED((unsigned long)base, 16))
59547ccb028SDave Martin goto invalid;
59647ccb028SDave Martin
597bb4891a6SDave Martin while (1) {
598bb4891a6SDave Martin int err = 0;
599bb4891a6SDave Martin u32 magic, size;
60033f08261SDave Martin char const __user *userp;
60133f08261SDave Martin struct extra_context const __user *extra;
60233f08261SDave Martin u64 extra_datap;
60333f08261SDave Martin u32 extra_size;
60433f08261SDave Martin struct _aarch64_ctx const __user *end;
60533f08261SDave Martin u32 end_magic, end_size;
606bb4891a6SDave Martin
607bb4891a6SDave Martin if (limit - offset < sizeof(*head))
608bb4891a6SDave Martin goto invalid;
609bb4891a6SDave Martin
610bb4891a6SDave Martin if (!IS_ALIGNED(offset, 16))
611bb4891a6SDave Martin goto invalid;
612bb4891a6SDave Martin
613bb4891a6SDave Martin head = (struct _aarch64_ctx __user *)(base + offset);
61447ccb028SDave Martin __get_user_error(magic, &head->magic, err);
61547ccb028SDave Martin __get_user_error(size, &head->size, err);
61647ccb028SDave Martin if (err)
61747ccb028SDave Martin return err;
61847ccb028SDave Martin
619bb4891a6SDave Martin if (limit - offset < size)
620bb4891a6SDave Martin goto invalid;
621bb4891a6SDave Martin
62247ccb028SDave Martin switch (magic) {
62347ccb028SDave Martin case 0:
62447ccb028SDave Martin if (size)
62547ccb028SDave Martin goto invalid;
62647ccb028SDave Martin
62747ccb028SDave Martin goto done;
62847ccb028SDave Martin
62947ccb028SDave Martin case FPSIMD_MAGIC:
6306d502b6bSSuzuki K Poulose if (!system_supports_fpsimd())
6316d502b6bSSuzuki K Poulose goto invalid;
63247ccb028SDave Martin if (user->fpsimd)
63347ccb028SDave Martin goto invalid;
63447ccb028SDave Martin
63547ccb028SDave Martin user->fpsimd = (struct fpsimd_context __user *)head;
636b57682b3SMark Brown user->fpsimd_size = size;
63747ccb028SDave Martin break;
63847ccb028SDave Martin
63947ccb028SDave Martin case ESR_MAGIC:
64047ccb028SDave Martin /* ignore */
64147ccb028SDave Martin break;
64247ccb028SDave Martin
6438cd969d2SDave Martin case SVE_MAGIC:
64485ed24daSMark Brown if (!system_supports_sve() && !system_supports_sme())
6458cd969d2SDave Martin goto invalid;
6468cd969d2SDave Martin
6478cd969d2SDave Martin if (user->sve)
6488cd969d2SDave Martin goto invalid;
6498cd969d2SDave Martin
6508cd969d2SDave Martin user->sve = (struct sve_context __user *)head;
651b57682b3SMark Brown user->sve_size = size;
6528cd969d2SDave Martin break;
6538cd969d2SDave Martin
65439e54499SMark Brown case TPIDR2_MAGIC:
655e9d14f3fSDongxu Sun if (!system_supports_tpidr2())
65647ccb028SDave Martin goto invalid;
65747ccb028SDave Martin
65839e54499SMark Brown if (user->tpidr2)
65939e54499SMark Brown goto invalid;
66039e54499SMark Brown
66139e54499SMark Brown user->tpidr2 = (struct tpidr2_context __user *)head;
662b57682b3SMark Brown user->tpidr2_size = size;
66347ccb028SDave Martin break;
66447ccb028SDave Martin
66539782210SMark Brown case ZA_MAGIC:
66639782210SMark Brown if (!system_supports_sme())
66739782210SMark Brown goto invalid;
66839782210SMark Brown
66939782210SMark Brown if (user->za)
67039782210SMark Brown goto invalid;
67139782210SMark Brown
67239782210SMark Brown user->za = (struct za_context __user *)head;
673b57682b3SMark Brown user->za_size = size;
67439782210SMark Brown break;
67539782210SMark Brown
676ee072cf7SMark Brown case ZT_MAGIC:
677ee072cf7SMark Brown if (!system_supports_sme2())
67847ccb028SDave Martin goto invalid;
67947ccb028SDave Martin
680ee072cf7SMark Brown if (user->zt)
681ee072cf7SMark Brown goto invalid;
682ee072cf7SMark Brown
683ee072cf7SMark Brown user->zt = (struct zt_context __user *)head;
684b57682b3SMark Brown user->zt_size = size;
68547ccb028SDave Martin break;
68647ccb028SDave Martin
68733f08261SDave Martin case EXTRA_MAGIC:
68833f08261SDave Martin if (have_extra_context)
68933f08261SDave Martin goto invalid;
69033f08261SDave Martin
69133f08261SDave Martin if (size < sizeof(*extra))
69233f08261SDave Martin goto invalid;
69333f08261SDave Martin
69433f08261SDave Martin userp = (char const __user *)head;
69533f08261SDave Martin
69633f08261SDave Martin extra = (struct extra_context const __user *)userp;
69733f08261SDave Martin userp += size;
69833f08261SDave Martin
69933f08261SDave Martin __get_user_error(extra_datap, &extra->datap, err);
70033f08261SDave Martin __get_user_error(extra_size, &extra->size, err);
70133f08261SDave Martin if (err)
70233f08261SDave Martin return err;
70333f08261SDave Martin
70433f08261SDave Martin /* Check for the dummy terminator in __reserved[]: */
70533f08261SDave Martin
70633f08261SDave Martin if (limit - offset - size < TERMINATOR_SIZE)
70733f08261SDave Martin goto invalid;
70833f08261SDave Martin
70933f08261SDave Martin end = (struct _aarch64_ctx const __user *)userp;
71033f08261SDave Martin userp += TERMINATOR_SIZE;
71133f08261SDave Martin
71233f08261SDave Martin __get_user_error(end_magic, &end->magic, err);
71333f08261SDave Martin __get_user_error(end_size, &end->size, err);
71433f08261SDave Martin if (err)
71533f08261SDave Martin return err;
71633f08261SDave Martin
71733f08261SDave Martin if (end_magic || end_size)
71833f08261SDave Martin goto invalid;
71933f08261SDave Martin
72033f08261SDave Martin /* Prevent looping/repeated parsing of extra_context */
72133f08261SDave Martin have_extra_context = true;
72233f08261SDave Martin
72333f08261SDave Martin base = (__force void __user *)extra_datap;
72433f08261SDave Martin if (!IS_ALIGNED((unsigned long)base, 16))
72533f08261SDave Martin goto invalid;
72633f08261SDave Martin
72733f08261SDave Martin if (!IS_ALIGNED(extra_size, 16))
72833f08261SDave Martin goto invalid;
72933f08261SDave Martin
73033f08261SDave Martin if (base != userp)
73133f08261SDave Martin goto invalid;
73233f08261SDave Martin
73333f08261SDave Martin /* Reject "unreasonably large" frames: */
73433f08261SDave Martin if (extra_size > sfp + SIGFRAME_MAXSZ - userp)
73533f08261SDave Martin goto invalid;
73633f08261SDave Martin
73733f08261SDave Martin /*
73833f08261SDave Martin * Ignore trailing terminator in __reserved[]
73933f08261SDave Martin * and start parsing extra data:
74033f08261SDave Martin */
74133f08261SDave Martin offset = 0;
74233f08261SDave Martin limit = extra_size;
743abf73988SDave Martin
74496d4f267SLinus Torvalds if (!access_ok(base, limit))
745abf73988SDave Martin goto invalid;
746abf73988SDave Martin
74733f08261SDave Martin continue;
74833f08261SDave Martin
74947ccb028SDave Martin default:
75047ccb028SDave Martin goto invalid;
75147ccb028SDave Martin }
75247ccb028SDave Martin
75347ccb028SDave Martin if (size < sizeof(*head))
75447ccb028SDave Martin goto invalid;
75547ccb028SDave Martin
756bb4891a6SDave Martin if (limit - offset < size)
75747ccb028SDave Martin goto invalid;
75847ccb028SDave Martin
75947ccb028SDave Martin offset += size;
76047ccb028SDave Martin }
76147ccb028SDave Martin
76247ccb028SDave Martin done:
76347ccb028SDave Martin return 0;
76447ccb028SDave Martin
76547ccb028SDave Martin invalid:
76647ccb028SDave Martin return -EINVAL;
76747ccb028SDave Martin }
76847ccb028SDave Martin
restore_sigframe(struct pt_regs * regs,struct rt_sigframe __user * sf)7692c020ed8SCatalin Marinas static int restore_sigframe(struct pt_regs *regs,
7702c020ed8SCatalin Marinas struct rt_sigframe __user *sf)
7712c020ed8SCatalin Marinas {
7722c020ed8SCatalin Marinas sigset_t set;
7732c020ed8SCatalin Marinas int i, err;
77447ccb028SDave Martin struct user_ctxs user;
7752c020ed8SCatalin Marinas
7762c020ed8SCatalin Marinas err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
7772c020ed8SCatalin Marinas if (err == 0)
7782c020ed8SCatalin Marinas set_current_blocked(&set);
7792c020ed8SCatalin Marinas
7802c020ed8SCatalin Marinas for (i = 0; i < 31; i++)
7812c020ed8SCatalin Marinas __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
7822c020ed8SCatalin Marinas err);
7832c020ed8SCatalin Marinas __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
7842c020ed8SCatalin Marinas __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
7852c020ed8SCatalin Marinas __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
7862c020ed8SCatalin Marinas
7872c020ed8SCatalin Marinas /*
7882c020ed8SCatalin Marinas * Avoid sys_rt_sigreturn() restarting.
7892c020ed8SCatalin Marinas */
79017c28958SDave Martin forget_syscall(regs);
7912c020ed8SCatalin Marinas
792dbd4d7caSMark Rutland err |= !valid_user_regs(®s->user_regs, current);
79347ccb028SDave Martin if (err == 0)
79447ccb028SDave Martin err = parse_user_sigframe(&user, sf);
7952c020ed8SCatalin Marinas
7966d502b6bSSuzuki K Poulose if (err == 0 && system_supports_fpsimd()) {
7978cd969d2SDave Martin if (!user.fpsimd)
7988cd969d2SDave Martin return -EINVAL;
7998cd969d2SDave Martin
800df07443fSMark Brown if (user.sve)
8018cd969d2SDave Martin err = restore_sve_fpsimd_context(&user);
802df07443fSMark Brown else
8034e4e9304SMark Brown err = restore_fpsimd_context(&user);
8048cd969d2SDave Martin }
8052c020ed8SCatalin Marinas
806e9d14f3fSDongxu Sun if (err == 0 && system_supports_tpidr2() && user.tpidr2)
80739e54499SMark Brown err = restore_tpidr2_context(&user);
80839e54499SMark Brown
80939782210SMark Brown if (err == 0 && system_supports_sme() && user.za)
81039782210SMark Brown err = restore_za_context(&user);
81139782210SMark Brown
812ee072cf7SMark Brown if (err == 0 && system_supports_sme2() && user.zt)
813ee072cf7SMark Brown err = restore_zt_context(&user);
814ee072cf7SMark Brown
8152c020ed8SCatalin Marinas return err;
8162c020ed8SCatalin Marinas }
8172c020ed8SCatalin Marinas
SYSCALL_DEFINE0(rt_sigreturn)818bf4ce5ccSMark Rutland SYSCALL_DEFINE0(rt_sigreturn)
8192c020ed8SCatalin Marinas {
8203085e164SMark Rutland struct pt_regs *regs = current_pt_regs();
8212c020ed8SCatalin Marinas struct rt_sigframe __user *frame;
8222c020ed8SCatalin Marinas
8232c020ed8SCatalin Marinas /* Always make any pending restarted system calls return -EINTR */
824f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall;
8252c020ed8SCatalin Marinas
8262c020ed8SCatalin Marinas /*
8272c020ed8SCatalin Marinas * Since we stacked the signal on a 128-bit boundary, then 'sp' should
8282c020ed8SCatalin Marinas * be word aligned here.
8292c020ed8SCatalin Marinas */
8302c020ed8SCatalin Marinas if (regs->sp & 15)
8312c020ed8SCatalin Marinas goto badframe;
8322c020ed8SCatalin Marinas
8332c020ed8SCatalin Marinas frame = (struct rt_sigframe __user *)regs->sp;
8342c020ed8SCatalin Marinas
83596d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame)))
8362c020ed8SCatalin Marinas goto badframe;
8372c020ed8SCatalin Marinas
8382c020ed8SCatalin Marinas if (restore_sigframe(regs, frame))
8392c020ed8SCatalin Marinas goto badframe;
8402c020ed8SCatalin Marinas
841207bdae4SAl Viro if (restore_altstack(&frame->uc.uc_stack))
8422c020ed8SCatalin Marinas goto badframe;
8432c020ed8SCatalin Marinas
8442c020ed8SCatalin Marinas return regs->regs[0];
8452c020ed8SCatalin Marinas
8462c020ed8SCatalin Marinas badframe:
847f71016a8SWill Deacon arm64_notify_segfault(regs->sp);
8482c020ed8SCatalin Marinas return 0;
8492c020ed8SCatalin Marinas }
8502c020ed8SCatalin Marinas
85194b07c1fSDave Martin /*
85294b07c1fSDave Martin * Determine the layout of optional records in the signal frame
85394b07c1fSDave Martin *
85494b07c1fSDave Martin * add_all: if true, lays out the biggest possible signal frame for
85594b07c1fSDave Martin * this task; otherwise, generates a layout for the current state
85694b07c1fSDave Martin * of the task.
85794b07c1fSDave Martin */
setup_sigframe_layout(struct rt_sigframe_user_layout * user,bool add_all)85894b07c1fSDave Martin static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
85994b07c1fSDave Martin bool add_all)
860bb4891a6SDave Martin {
861bb4322f7SDave Martin int err;
862bb4322f7SDave Martin
8630a32c88dSDavid Engraf if (system_supports_fpsimd()) {
864bb4322f7SDave Martin err = sigframe_alloc(user, &user->fpsimd_offset,
865bb4322f7SDave Martin sizeof(struct fpsimd_context));
866bb4322f7SDave Martin if (err)
867bb4322f7SDave Martin return err;
8680a32c88dSDavid Engraf }
869bb4891a6SDave Martin
870bb4891a6SDave Martin /* fault information, if valid */
87194b07c1fSDave Martin if (add_all || current->thread.fault_code) {
872bb4322f7SDave Martin err = sigframe_alloc(user, &user->esr_offset,
873bb4322f7SDave Martin sizeof(struct esr_context));
874bb4322f7SDave Martin if (err)
875bb4322f7SDave Martin return err;
876bb4891a6SDave Martin }
877bb4891a6SDave Martin
878f26cd737SMark Brown if (system_supports_sve() || system_supports_sme()) {
8798cd969d2SDave Martin unsigned int vq = 0;
8808cd969d2SDave Martin
881*60480c6bSMark Brown if (add_all || current->thread.fp_type == FP_STATE_SVE ||
88285ed24daSMark Brown thread_sm_enabled(¤t->thread)) {
88385ed24daSMark Brown int vl = max(sve_max_vl(), sme_max_vl());
88494b07c1fSDave Martin
88594b07c1fSDave Martin if (!add_all)
88685ed24daSMark Brown vl = thread_get_cur_vl(¤t->thread);
88794b07c1fSDave Martin
88894b07c1fSDave Martin vq = sve_vq_from_vl(vl);
88994b07c1fSDave Martin }
8908cd969d2SDave Martin
8918cd969d2SDave Martin err = sigframe_alloc(user, &user->sve_offset,
8928cd969d2SDave Martin SVE_SIG_CONTEXT_SIZE(vq));
8938cd969d2SDave Martin if (err)
8948cd969d2SDave Martin return err;
8958cd969d2SDave Martin }
8968cd969d2SDave Martin
89719e99e7dSDongxu Sun if (system_supports_tpidr2()) {
89819e99e7dSDongxu Sun err = sigframe_alloc(user, &user->tpidr2_offset,
89919e99e7dSDongxu Sun sizeof(struct tpidr2_context));
90019e99e7dSDongxu Sun if (err)
90119e99e7dSDongxu Sun return err;
90219e99e7dSDongxu Sun }
90319e99e7dSDongxu Sun
90439782210SMark Brown if (system_supports_sme()) {
90539782210SMark Brown unsigned int vl;
90639782210SMark Brown unsigned int vq = 0;
90739782210SMark Brown
90839782210SMark Brown if (add_all)
90939782210SMark Brown vl = sme_max_vl();
91039782210SMark Brown else
91139782210SMark Brown vl = task_get_sme_vl(current);
91239782210SMark Brown
91339782210SMark Brown if (thread_za_enabled(¤t->thread))
91439782210SMark Brown vq = sve_vq_from_vl(vl);
91539782210SMark Brown
91639782210SMark Brown err = sigframe_alloc(user, &user->za_offset,
91739782210SMark Brown ZA_SIG_CONTEXT_SIZE(vq));
91839782210SMark Brown if (err)
91939782210SMark Brown return err;
92039782210SMark Brown }
92139782210SMark Brown
922ee072cf7SMark Brown if (system_supports_sme2()) {
923ee072cf7SMark Brown if (add_all || thread_za_enabled(¤t->thread)) {
924ee072cf7SMark Brown err = sigframe_alloc(user, &user->zt_offset,
925ee072cf7SMark Brown ZT_SIG_CONTEXT_SIZE(1));
926ee072cf7SMark Brown if (err)
927ee072cf7SMark Brown return err;
928ee072cf7SMark Brown }
929ee072cf7SMark Brown }
930ee072cf7SMark Brown
93133f08261SDave Martin return sigframe_alloc_end(user);
932bb4891a6SDave Martin }
933bb4891a6SDave Martin
setup_sigframe(struct rt_sigframe_user_layout * user,struct pt_regs * regs,sigset_t * set)93420987de3SDave Martin static int setup_sigframe(struct rt_sigframe_user_layout *user,
9352c020ed8SCatalin Marinas struct pt_regs *regs, sigset_t *set)
9362c020ed8SCatalin Marinas {
9372c020ed8SCatalin Marinas int i, err = 0;
93820987de3SDave Martin struct rt_sigframe __user *sf = user->sigframe;
9392c020ed8SCatalin Marinas
940304ef4e8SWill Deacon /* set up the stack frame for unwinding */
94120987de3SDave Martin __put_user_error(regs->regs[29], &user->next_frame->fp, err);
94220987de3SDave Martin __put_user_error(regs->regs[30], &user->next_frame->lr, err);
943304ef4e8SWill Deacon
9442c020ed8SCatalin Marinas for (i = 0; i < 31; i++)
9452c020ed8SCatalin Marinas __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
9462c020ed8SCatalin Marinas err);
9472c020ed8SCatalin Marinas __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
9482c020ed8SCatalin Marinas __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
9492c020ed8SCatalin Marinas __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
9502c020ed8SCatalin Marinas
9512c020ed8SCatalin Marinas __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
9522c020ed8SCatalin Marinas
9532c020ed8SCatalin Marinas err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
9542c020ed8SCatalin Marinas
9556d502b6bSSuzuki K Poulose if (err == 0 && system_supports_fpsimd()) {
956bb4891a6SDave Martin struct fpsimd_context __user *fpsimd_ctx =
957bb4891a6SDave Martin apply_user_offset(user, user->fpsimd_offset);
9580e0276d1SCatalin Marinas err |= preserve_fpsimd_context(fpsimd_ctx);
9590e0276d1SCatalin Marinas }
9602c020ed8SCatalin Marinas
96115af1942SCatalin Marinas /* fault information, if valid */
962bb4891a6SDave Martin if (err == 0 && user->esr_offset) {
963bb4891a6SDave Martin struct esr_context __user *esr_ctx =
964bb4891a6SDave Martin apply_user_offset(user, user->esr_offset);
965bb4891a6SDave Martin
96615af1942SCatalin Marinas __put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err);
96715af1942SCatalin Marinas __put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err);
96815af1942SCatalin Marinas __put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
96915af1942SCatalin Marinas }
97015af1942SCatalin Marinas
97185ed24daSMark Brown /* Scalable Vector Extension state (including streaming), if present */
97285ed24daSMark Brown if ((system_supports_sve() || system_supports_sme()) &&
97385ed24daSMark Brown err == 0 && user->sve_offset) {
9748cd969d2SDave Martin struct sve_context __user *sve_ctx =
9758cd969d2SDave Martin apply_user_offset(user, user->sve_offset);
9768cd969d2SDave Martin err |= preserve_sve_context(sve_ctx);
9778cd969d2SDave Martin }
9788cd969d2SDave Martin
97939e54499SMark Brown /* TPIDR2 if supported */
980e9d14f3fSDongxu Sun if (system_supports_tpidr2() && err == 0) {
98139e54499SMark Brown struct tpidr2_context __user *tpidr2_ctx =
98239e54499SMark Brown apply_user_offset(user, user->tpidr2_offset);
98339e54499SMark Brown err |= preserve_tpidr2_context(tpidr2_ctx);
98439e54499SMark Brown }
98539e54499SMark Brown
98639782210SMark Brown /* ZA state if present */
98739782210SMark Brown if (system_supports_sme() && err == 0 && user->za_offset) {
98839782210SMark Brown struct za_context __user *za_ctx =
98939782210SMark Brown apply_user_offset(user, user->za_offset);
99039782210SMark Brown err |= preserve_za_context(za_ctx);
99139782210SMark Brown }
99239782210SMark Brown
993ee072cf7SMark Brown /* ZT state if present */
994ee072cf7SMark Brown if (system_supports_sme2() && err == 0 && user->zt_offset) {
995ee072cf7SMark Brown struct zt_context __user *zt_ctx =
996ee072cf7SMark Brown apply_user_offset(user, user->zt_offset);
997ee072cf7SMark Brown err |= preserve_zt_context(zt_ctx);
998ee072cf7SMark Brown }
999ee072cf7SMark Brown
100033f08261SDave Martin if (err == 0 && user->extra_offset) {
100133f08261SDave Martin char __user *sfp = (char __user *)user->sigframe;
100233f08261SDave Martin char __user *userp =
100333f08261SDave Martin apply_user_offset(user, user->extra_offset);
100433f08261SDave Martin
100533f08261SDave Martin struct extra_context __user *extra;
100633f08261SDave Martin struct _aarch64_ctx __user *end;
100733f08261SDave Martin u64 extra_datap;
100833f08261SDave Martin u32 extra_size;
100933f08261SDave Martin
101033f08261SDave Martin extra = (struct extra_context __user *)userp;
101133f08261SDave Martin userp += EXTRA_CONTEXT_SIZE;
101233f08261SDave Martin
101333f08261SDave Martin end = (struct _aarch64_ctx __user *)userp;
101433f08261SDave Martin userp += TERMINATOR_SIZE;
101533f08261SDave Martin
101633f08261SDave Martin /*
101733f08261SDave Martin * extra_datap is just written to the signal frame.
101833f08261SDave Martin * The value gets cast back to a void __user *
101933f08261SDave Martin * during sigreturn.
102033f08261SDave Martin */
102133f08261SDave Martin extra_datap = (__force u64)userp;
102233f08261SDave Martin extra_size = sfp + round_up(user->size, 16) - userp;
102333f08261SDave Martin
102433f08261SDave Martin __put_user_error(EXTRA_MAGIC, &extra->head.magic, err);
102533f08261SDave Martin __put_user_error(EXTRA_CONTEXT_SIZE, &extra->head.size, err);
102633f08261SDave Martin __put_user_error(extra_datap, &extra->datap, err);
102733f08261SDave Martin __put_user_error(extra_size, &extra->size, err);
102833f08261SDave Martin
102933f08261SDave Martin /* Add the terminator */
103033f08261SDave Martin __put_user_error(0, &end->magic, err);
103133f08261SDave Martin __put_user_error(0, &end->size, err);
103233f08261SDave Martin }
103333f08261SDave Martin
10342c020ed8SCatalin Marinas /* set the "end" magic */
1035bb4891a6SDave Martin if (err == 0) {
1036bb4891a6SDave Martin struct _aarch64_ctx __user *end =
1037bb4891a6SDave Martin apply_user_offset(user, user->end_offset);
1038bb4891a6SDave Martin
10390e0276d1SCatalin Marinas __put_user_error(0, &end->magic, err);
10400e0276d1SCatalin Marinas __put_user_error(0, &end->size, err);
1041bb4891a6SDave Martin }
10422c020ed8SCatalin Marinas
10432c020ed8SCatalin Marinas return err;
10442c020ed8SCatalin Marinas }
10452c020ed8SCatalin Marinas
get_sigframe(struct rt_sigframe_user_layout * user,struct ksignal * ksig,struct pt_regs * regs)104620987de3SDave Martin static int get_sigframe(struct rt_sigframe_user_layout *user,
104720987de3SDave Martin struct ksignal *ksig, struct pt_regs *regs)
10482c020ed8SCatalin Marinas {
10492c020ed8SCatalin Marinas unsigned long sp, sp_top;
1050bb4891a6SDave Martin int err;
1051bb4891a6SDave Martin
1052bb4891a6SDave Martin init_user_layout(user);
105394b07c1fSDave Martin err = setup_sigframe_layout(user, false);
1054bb4891a6SDave Martin if (err)
1055bb4891a6SDave Martin return err;
10562c020ed8SCatalin Marinas
105738a7be3cSRichard Weinberger sp = sp_top = sigsp(regs->sp, ksig);
10582c020ed8SCatalin Marinas
105920987de3SDave Martin sp = round_down(sp - sizeof(struct frame_record), 16);
106020987de3SDave Martin user->next_frame = (struct frame_record __user *)sp;
106120987de3SDave Martin
1062bb4891a6SDave Martin sp = round_down(sp, 16) - sigframe_size(user);
106320987de3SDave Martin user->sigframe = (struct rt_sigframe __user *)sp;
10642c020ed8SCatalin Marinas
10652c020ed8SCatalin Marinas /*
10662c020ed8SCatalin Marinas * Check that we can actually write to the signal frame.
10672c020ed8SCatalin Marinas */
106896d4f267SLinus Torvalds if (!access_ok(user->sigframe, sp_top - sp))
106920987de3SDave Martin return -EFAULT;
10702c020ed8SCatalin Marinas
107120987de3SDave Martin return 0;
10722c020ed8SCatalin Marinas }
10732c020ed8SCatalin Marinas
setup_return(struct pt_regs * regs,struct k_sigaction * ka,struct rt_sigframe_user_layout * user,int usig)1074304ef4e8SWill Deacon static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
107520987de3SDave Martin struct rt_sigframe_user_layout *user, int usig)
10762c020ed8SCatalin Marinas {
10772c020ed8SCatalin Marinas __sigrestore_t sigtramp;
10782c020ed8SCatalin Marinas
10792c020ed8SCatalin Marinas regs->regs[0] = usig;
108020987de3SDave Martin regs->sp = (unsigned long)user->sigframe;
108120987de3SDave Martin regs->regs[29] = (unsigned long)&user->next_frame->fp;
10822c020ed8SCatalin Marinas regs->pc = (unsigned long)ka->sa.sa_handler;
10832c020ed8SCatalin Marinas
10848ef8f360SDave Martin /*
10858ef8f360SDave Martin * Signal delivery is a (wacky) indirect function call in
10868ef8f360SDave Martin * userspace, so simulate the same setting of BTYPE as a BLR
10878ef8f360SDave Martin * <register containing the signal handler entry point>.
10888ef8f360SDave Martin * Signal delivery to a location in a PROT_BTI guarded page
10898ef8f360SDave Martin * that is not a function entry point will now trigger a
10908ef8f360SDave Martin * SIGILL in userspace.
10918ef8f360SDave Martin *
10928ef8f360SDave Martin * If the signal handler entry point is not in a PROT_BTI
10938ef8f360SDave Martin * guarded page, this is harmless.
10948ef8f360SDave Martin */
10958ef8f360SDave Martin if (system_supports_bti()) {
10968ef8f360SDave Martin regs->pstate &= ~PSR_BTYPE_MASK;
10978ef8f360SDave Martin regs->pstate |= PSR_BTYPE_C;
10988ef8f360SDave Martin }
10998ef8f360SDave Martin
1100637ec831SVincenzo Frascino /* TCO (Tag Check Override) always cleared for signal handlers */
1101637ec831SVincenzo Frascino regs->pstate &= ~PSR_TCO_BIT;
1102637ec831SVincenzo Frascino
110340a8e87bSMark Brown /* Signal handlers are invoked with ZA and streaming mode disabled */
110440a8e87bSMark Brown if (system_supports_sme()) {
1105ea64baacSMark Brown /*
1106ea64baacSMark Brown * If we were in streaming mode the saved register
1107ea64baacSMark Brown * state was SVE but we will exit SM and use the
1108ea64baacSMark Brown * FPSIMD register state - flush the saved FPSIMD
1109ea64baacSMark Brown * register state in case it gets loaded.
1110ea64baacSMark Brown */
1111baa85152SMark Brown if (current->thread.svcr & SVCR_SM_MASK) {
1112ea64baacSMark Brown memset(¤t->thread.uw.fpsimd_state, 0,
1113ea64baacSMark Brown sizeof(current->thread.uw.fpsimd_state));
1114baa85152SMark Brown current->thread.fp_type = FP_STATE_FPSIMD;
1115baa85152SMark Brown }
1116ea64baacSMark Brown
1117ec0067a6SMark Brown current->thread.svcr &= ~(SVCR_ZA_MASK |
1118ec0067a6SMark Brown SVCR_SM_MASK);
111940a8e87bSMark Brown sme_smstop();
112040a8e87bSMark Brown }
112140a8e87bSMark Brown
11222c020ed8SCatalin Marinas if (ka->sa.sa_flags & SA_RESTORER)
11232c020ed8SCatalin Marinas sigtramp = ka->sa.sa_restorer;
11242c020ed8SCatalin Marinas else
11252c020ed8SCatalin Marinas sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
11262c020ed8SCatalin Marinas
11272c020ed8SCatalin Marinas regs->regs[30] = (unsigned long)sigtramp;
11282c020ed8SCatalin Marinas }
11292c020ed8SCatalin Marinas
setup_rt_frame(int usig,struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)113000554fa4SRichard Weinberger static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
113100554fa4SRichard Weinberger struct pt_regs *regs)
11322c020ed8SCatalin Marinas {
113320987de3SDave Martin struct rt_sigframe_user_layout user;
11342c020ed8SCatalin Marinas struct rt_sigframe __user *frame;
11352c020ed8SCatalin Marinas int err = 0;
11362c020ed8SCatalin Marinas
11378cd969d2SDave Martin fpsimd_signal_preserve_current_state();
11388cd969d2SDave Martin
113920987de3SDave Martin if (get_sigframe(&user, ksig, regs))
11402c020ed8SCatalin Marinas return 1;
11412c020ed8SCatalin Marinas
114220987de3SDave Martin frame = user.sigframe;
114320987de3SDave Martin
11442c020ed8SCatalin Marinas __put_user_error(0, &frame->uc.uc_flags, err);
11452c020ed8SCatalin Marinas __put_user_error(NULL, &frame->uc.uc_link, err);
11462c020ed8SCatalin Marinas
1147207bdae4SAl Viro err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
114820987de3SDave Martin err |= setup_sigframe(&user, regs, set);
1149304ef4e8SWill Deacon if (err == 0) {
115020987de3SDave Martin setup_return(regs, &ksig->ka, &user, usig);
115100554fa4SRichard Weinberger if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
115200554fa4SRichard Weinberger err |= copy_siginfo_to_user(&frame->info, &ksig->info);
11532c020ed8SCatalin Marinas regs->regs[1] = (unsigned long)&frame->info;
11542c020ed8SCatalin Marinas regs->regs[2] = (unsigned long)&frame->uc;
11552c020ed8SCatalin Marinas }
1156304ef4e8SWill Deacon }
11572c020ed8SCatalin Marinas
11582c020ed8SCatalin Marinas return err;
11592c020ed8SCatalin Marinas }
11602c020ed8SCatalin Marinas
setup_restart_syscall(struct pt_regs * regs)11612c020ed8SCatalin Marinas static void setup_restart_syscall(struct pt_regs *regs)
11622c020ed8SCatalin Marinas {
11632c020ed8SCatalin Marinas if (is_compat_task())
11642c020ed8SCatalin Marinas compat_setup_restart_syscall(regs);
11652c020ed8SCatalin Marinas else
11662c020ed8SCatalin Marinas regs->regs[8] = __NR_restart_syscall;
11672c020ed8SCatalin Marinas }
11682c020ed8SCatalin Marinas
11692c020ed8SCatalin Marinas /*
11702c020ed8SCatalin Marinas * OK, we're invoking a handler
11712c020ed8SCatalin Marinas */
handle_signal(struct ksignal * ksig,struct pt_regs * regs)117200554fa4SRichard Weinberger static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
11732c020ed8SCatalin Marinas {
11742c020ed8SCatalin Marinas sigset_t *oldset = sigmask_to_save();
117500554fa4SRichard Weinberger int usig = ksig->sig;
11762c020ed8SCatalin Marinas int ret;
11772c020ed8SCatalin Marinas
1178409d5db4SWill Deacon rseq_signal_deliver(ksig, regs);
1179409d5db4SWill Deacon
11802c020ed8SCatalin Marinas /*
11812c020ed8SCatalin Marinas * Set up the stack frame
11822c020ed8SCatalin Marinas */
11832c020ed8SCatalin Marinas if (is_compat_task()) {
118400554fa4SRichard Weinberger if (ksig->ka.sa.sa_flags & SA_SIGINFO)
118500554fa4SRichard Weinberger ret = compat_setup_rt_frame(usig, ksig, oldset, regs);
11862c020ed8SCatalin Marinas else
118700554fa4SRichard Weinberger ret = compat_setup_frame(usig, ksig, oldset, regs);
11882c020ed8SCatalin Marinas } else {
118900554fa4SRichard Weinberger ret = setup_rt_frame(usig, ksig, oldset, regs);
11902c020ed8SCatalin Marinas }
11912c020ed8SCatalin Marinas
11922c020ed8SCatalin Marinas /*
11932c020ed8SCatalin Marinas * Check that the resulting registers are actually sane.
11942c020ed8SCatalin Marinas */
1195dbd4d7caSMark Rutland ret |= !valid_user_regs(®s->user_regs, current);
11962c020ed8SCatalin Marinas
1197ac2081cdSWill Deacon /* Step into the signal handler if we are stepping */
1198ac2081cdSWill Deacon signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
11992c020ed8SCatalin Marinas }
12002c020ed8SCatalin Marinas
12012c020ed8SCatalin Marinas /*
12022c020ed8SCatalin Marinas * Note that 'init' is a special process: it doesn't get signals it doesn't
12032c020ed8SCatalin Marinas * want to handle. Thus you cannot kill init even with a SIGKILL even by
12042c020ed8SCatalin Marinas * mistake.
12052c020ed8SCatalin Marinas *
12062c020ed8SCatalin Marinas * Note that we go through the signals twice: once to check the signals that
12072c020ed8SCatalin Marinas * the kernel can handle, and then we build all the user-level signal handling
12082c020ed8SCatalin Marinas * stack-frames in one go after that.
12092c020ed8SCatalin Marinas */
do_signal(struct pt_regs * regs)12102c020ed8SCatalin Marinas static void do_signal(struct pt_regs *regs)
12112c020ed8SCatalin Marinas {
12122c020ed8SCatalin Marinas unsigned long continue_addr = 0, restart_addr = 0;
121300554fa4SRichard Weinberger int retval = 0;
121400554fa4SRichard Weinberger struct ksignal ksig;
12150fe42512SDave Martin bool syscall = in_syscall(regs);
12162c020ed8SCatalin Marinas
12172c020ed8SCatalin Marinas /*
12182c020ed8SCatalin Marinas * If we were from a system call, check for system call restarting...
12192c020ed8SCatalin Marinas */
12200fe42512SDave Martin if (syscall) {
12212c020ed8SCatalin Marinas continue_addr = regs->pc;
12222c020ed8SCatalin Marinas restart_addr = continue_addr - (compat_thumb_mode(regs) ? 2 : 4);
12232c020ed8SCatalin Marinas retval = regs->regs[0];
12242c020ed8SCatalin Marinas
12252c020ed8SCatalin Marinas /*
12262c020ed8SCatalin Marinas * Avoid additional syscall restarting via ret_to_user.
12272c020ed8SCatalin Marinas */
122817c28958SDave Martin forget_syscall(regs);
12292c020ed8SCatalin Marinas
12302c020ed8SCatalin Marinas /*
12312c020ed8SCatalin Marinas * Prepare for system call restart. We do this here so that a
12322c020ed8SCatalin Marinas * debugger will see the already changed PC.
12332c020ed8SCatalin Marinas */
12342c020ed8SCatalin Marinas switch (retval) {
12352c020ed8SCatalin Marinas case -ERESTARTNOHAND:
12362c020ed8SCatalin Marinas case -ERESTARTSYS:
12372c020ed8SCatalin Marinas case -ERESTARTNOINTR:
12382c020ed8SCatalin Marinas case -ERESTART_RESTARTBLOCK:
12392c020ed8SCatalin Marinas regs->regs[0] = regs->orig_x0;
12402c020ed8SCatalin Marinas regs->pc = restart_addr;
12412c020ed8SCatalin Marinas break;
12422c020ed8SCatalin Marinas }
12432c020ed8SCatalin Marinas }
12442c020ed8SCatalin Marinas
12452c020ed8SCatalin Marinas /*
12462c020ed8SCatalin Marinas * Get the signal to deliver. When running under ptrace, at this point
12472c020ed8SCatalin Marinas * the debugger may change all of our registers.
12482c020ed8SCatalin Marinas */
124900554fa4SRichard Weinberger if (get_signal(&ksig)) {
12502c020ed8SCatalin Marinas /*
12512c020ed8SCatalin Marinas * Depending on the signal settings, we may need to revert the
12522c020ed8SCatalin Marinas * decision to restart the system call, but skip this if a
12532c020ed8SCatalin Marinas * debugger has chosen to restart at a different PC.
12542c020ed8SCatalin Marinas */
12552c020ed8SCatalin Marinas if (regs->pc == restart_addr &&
12562c020ed8SCatalin Marinas (retval == -ERESTARTNOHAND ||
12572c020ed8SCatalin Marinas retval == -ERESTART_RESTARTBLOCK ||
12582c020ed8SCatalin Marinas (retval == -ERESTARTSYS &&
125900554fa4SRichard Weinberger !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
1260e30e8d46SMark Rutland syscall_set_return_value(current, regs, -EINTR, 0);
12612c020ed8SCatalin Marinas regs->pc = continue_addr;
12622c020ed8SCatalin Marinas }
12632c020ed8SCatalin Marinas
126400554fa4SRichard Weinberger handle_signal(&ksig, regs);
12652c020ed8SCatalin Marinas return;
12662c020ed8SCatalin Marinas }
12672c020ed8SCatalin Marinas
12682c020ed8SCatalin Marinas /*
12692c020ed8SCatalin Marinas * Handle restarting a different system call. As above, if a debugger
12702c020ed8SCatalin Marinas * has chosen to restart at a different PC, ignore the restart.
12712c020ed8SCatalin Marinas */
12720fe42512SDave Martin if (syscall && regs->pc == restart_addr) {
12732c020ed8SCatalin Marinas if (retval == -ERESTART_RESTARTBLOCK)
12742c020ed8SCatalin Marinas setup_restart_syscall(regs);
12752c020ed8SCatalin Marinas user_rewind_single_step(current);
12762c020ed8SCatalin Marinas }
12772c020ed8SCatalin Marinas
12782c020ed8SCatalin Marinas restore_saved_sigmask();
12792c020ed8SCatalin Marinas }
12802c020ed8SCatalin Marinas
do_notify_resume(struct pt_regs * regs,unsigned long thread_flags)12814d1c2ee2SMark Rutland void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags)
12822c020ed8SCatalin Marinas {
1283a2048e34SThomas Garnier do {
1284421dd6faSChris Metcalf if (thread_flags & _TIF_NEED_RESCHED) {
12858d66772eSJames Morse /* Unmask Debug and SError for the next task */
12868d66772eSJames Morse local_daif_restore(DAIF_PROCCTX_NOIRQ);
12878d66772eSJames Morse
1288421dd6faSChris Metcalf schedule();
1289421dd6faSChris Metcalf } else {
12908d66772eSJames Morse local_daif_restore(DAIF_PROCCTX);
1291421dd6faSChris Metcalf
12929842ceaeSPratyush Anand if (thread_flags & _TIF_UPROBE)
12939842ceaeSPratyush Anand uprobe_notify_resume(regs);
12949842ceaeSPratyush Anand
1295637ec831SVincenzo Frascino if (thread_flags & _TIF_MTE_ASYNC_FAULT) {
1296637ec831SVincenzo Frascino clear_thread_flag(TIF_MTE_ASYNC_FAULT);
1297637ec831SVincenzo Frascino send_sig_fault(SIGSEGV, SEGV_MTEAERR,
1298637ec831SVincenzo Frascino (void __user *)NULL, current);
1299637ec831SVincenzo Frascino }
1300637ec831SVincenzo Frascino
1301192caabdSJens Axboe if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL))
13022c020ed8SCatalin Marinas do_signal(regs);
13032c020ed8SCatalin Marinas
1304a68de80fSSean Christopherson if (thread_flags & _TIF_NOTIFY_RESUME)
130503248addSEric W. Biederman resume_user_mode_work(regs);
1306005f78cdSArd Biesheuvel
1307005f78cdSArd Biesheuvel if (thread_flags & _TIF_FOREIGN_FPSTATE)
1308005f78cdSArd Biesheuvel fpsimd_restore_current_state();
1309421dd6faSChris Metcalf }
1310005f78cdSArd Biesheuvel
13118d66772eSJames Morse local_daif_mask();
1312342b3808SMark Rutland thread_flags = read_thread_flags();
1313421dd6faSChris Metcalf } while (thread_flags & _TIF_WORK_MASK);
13142c020ed8SCatalin Marinas }
131594b07c1fSDave Martin
131694b07c1fSDave Martin unsigned long __ro_after_init signal_minsigstksz;
131794b07c1fSDave Martin
131894b07c1fSDave Martin /*
131994b07c1fSDave Martin * Determine the stack space required for guaranteed signal devliery.
132094b07c1fSDave Martin * This function is used to populate AT_MINSIGSTKSZ at process startup.
132194b07c1fSDave Martin * cpufeatures setup is assumed to be complete.
132294b07c1fSDave Martin */
minsigstksz_setup(void)132394b07c1fSDave Martin void __init minsigstksz_setup(void)
132494b07c1fSDave Martin {
132594b07c1fSDave Martin struct rt_sigframe_user_layout user;
132694b07c1fSDave Martin
132794b07c1fSDave Martin init_user_layout(&user);
132894b07c1fSDave Martin
132994b07c1fSDave Martin /*
133094b07c1fSDave Martin * If this fails, SIGFRAME_MAXSZ needs to be enlarged. It won't
133194b07c1fSDave Martin * be big enough, but it's our best guess:
133294b07c1fSDave Martin */
133394b07c1fSDave Martin if (WARN_ON(setup_sigframe_layout(&user, true)))
133494b07c1fSDave Martin return;
133594b07c1fSDave Martin
133694b07c1fSDave Martin signal_minsigstksz = sigframe_size(&user) +
133794b07c1fSDave Martin round_up(sizeof(struct frame_record), 16) +
133894b07c1fSDave Martin 16; /* max alignment padding */
133994b07c1fSDave Martin }
1340726e337bSMarco Elver
1341726e337bSMarco Elver /*
1342726e337bSMarco Elver * Compile-time assertions for siginfo_t offsets. Check NSIG* as well, as
1343726e337bSMarco Elver * changes likely come with new fields that should be added below.
1344726e337bSMarco Elver */
1345726e337bSMarco Elver static_assert(NSIGILL == 11);
1346726e337bSMarco Elver static_assert(NSIGFPE == 15);
1347a5f6c2acSRick Edgecombe static_assert(NSIGSEGV == 10);
1348726e337bSMarco Elver static_assert(NSIGBUS == 5);
1349726e337bSMarco Elver static_assert(NSIGTRAP == 6);
1350726e337bSMarco Elver static_assert(NSIGCHLD == 6);
1351726e337bSMarco Elver static_assert(NSIGSYS == 2);
135250ae8130SEric W. Biederman static_assert(sizeof(siginfo_t) == 128);
135350ae8130SEric W. Biederman static_assert(__alignof__(siginfo_t) == 8);
1354726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_signo) == 0x00);
1355726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_errno) == 0x04);
1356726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_code) == 0x08);
1357726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_pid) == 0x10);
1358726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_uid) == 0x14);
1359726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_tid) == 0x10);
1360726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_overrun) == 0x14);
1361726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_status) == 0x18);
1362726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_utime) == 0x20);
1363726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_stime) == 0x28);
1364726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_value) == 0x18);
1365726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_int) == 0x18);
1366726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_ptr) == 0x18);
1367726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_addr) == 0x10);
1368726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_addr_lsb) == 0x18);
1369726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_lower) == 0x20);
1370726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_upper) == 0x28);
1371726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_pkey) == 0x20);
1372726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_perf_data) == 0x18);
1373726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_perf_type) == 0x20);
137478ed93d7SMarco Elver static_assert(offsetof(siginfo_t, si_perf_flags) == 0x24);
1375726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_band) == 0x10);
1376726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_fd) == 0x18);
1377726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_call_addr) == 0x10);
1378726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_syscall) == 0x18);
1379726e337bSMarco Elver static_assert(offsetof(siginfo_t, si_arch) == 0x1c);
1380