/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <linux/cache.h>
#include <linux/context_tracking.h>
#include <linux/irqflags.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/personality.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/uprobes.h>
#include <linux/compiler.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
#include <asm/abi.h>
#include <asm/asm.h>
#include <linux/bitops.h>
#include <asm/cacheflush.h>
#include <asm/fpu.h>
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
#include <asm/dsp.h>
#include <asm/inst.h>
#include <asm/msa.h>
#include "signal-common.h"
static int (*save_fp_context)(void __user *sc);
static int (*restore_fp_context)(void __user *sc);
struct sigframe {
u32 sf_ass[4]; /* argument save space for o32 */
u32 sf_pad[2]; /* Was: signal trampoline */
/* Matches struct ucontext from its uc_mcontext field onwards */
struct sigcontext sf_sc;
sigset_t sf_mask;
unsigned long long sf_extcontext[0];
};
struct rt_sigframe {
u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_pad[2]; /* Was: signal trampoline */
struct siginfo rs_info;
struct ucontext rs_uc;
};
/*
* Thread saved context copy to/from a signal context presumed to be on the
* user stack, and therefore accessed with appropriate macros from uaccess.h.
*/
static int copy_fp_to_sigcontext(void __user *sc)
{
struct mips_abi *abi = current->thread.abi;
uint64_t __user *fpregs = sc + abi->off_sc_fpregs;
uint32_t __user *csr = sc + abi->off_sc_fpc_csr;
int i;
int err = 0;
int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
for (i = 0; i < NUM_FPU_REGS; i += inc) {
err |=
__put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0),
&fpregs[i]);
}
err |= __put_user(current->thread.fpu.fcr31, csr);
return err;
}
static int copy_fp_from_sigcontext(void __user *sc)
{
struct mips_abi *abi = current->thread.abi;
uint64_t __user *fpregs = sc + abi->off_sc_fpregs;
uint32_t __user *csr = sc + abi->off_sc_fpc_csr;
int i;
int err = 0;
int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
u64 fpr_val;
for (i = 0; i < NUM_FPU_REGS; i += inc) {
err |= __get_user(fpr_val, &fpregs[i]);
set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val);
}
err |= __get_user(current->thread.fpu.fcr31, csr);
return err;
}
/*
* Wrappers for the assembly _{save,restore}_fp_context functions.
*/
static int save_hw_fp_context(void __user *sc)
{
struct mips_abi *abi = current->thread.abi;
uint64_t __user *fpregs = sc + abi->off_sc_fpregs;
uint32_t __user *csr = sc + abi->off_sc_fpc_csr;
return _save_fp_context(fpregs, csr);
}
static int restore_hw_fp_context(void __user *sc)
{
struct mips_abi *abi = current->thread.abi;
uint64_t __user *fpregs = sc + abi->off_sc_fpregs;
uint32_t __user *csr = sc + abi->off_sc_fpc_csr;
return _restore_fp_context(fpregs, csr);
}
/*
* Extended context handling.
*/
static inline void __user *sc_to_extcontext(void __user *sc)
{
struct ucontext __user *uc;
/*
* We can just pretend the sigcontext is always embedded in a struct
* ucontext here, because the offset from sigcontext to extended
* context is the same in the struct sigframe case.
*/
uc = container_of(sc, struct ucontext, uc_mcontext);
return &uc->uc_extcontext;
}
static int save_msa_extcontext(void __user *buf)
{
struct msa_extcontext __user *msa = buf;
uint64_t val;
int i, err;
if (!thread_msa_context_live())
return 0;
/*
* Ensure that we can't lose the live MSA context between checking
* for it & writing it to memory.
*/
preempt_disable();
if (is_msa_enabled()) {
/*
* There are no EVA versions of the vector register load/store
* instructions, so MSA context has to be saved to kernel memory
* and then copi