summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/process_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/process_64.c')
-rw-r--r--arch/sparc/kernel/process_64.c214
1 files changed, 67 insertions, 147 deletions
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index b96104da5bd6..25781923788a 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996, 2008 David S. Miller (davem@davemloft.net)
@@ -8,9 +9,6 @@
/*
* This file handles the architecture-dependent parts of process handling..
*/
-
-#include <stdarg.h>
-
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/sched.h>
@@ -35,11 +33,11 @@
#include <linux/sysrq.h>
#include <linux/nmi.h>
#include <linux/context_tracking.h>
+#include <linux/signal.h>
#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/pstate.h>
#include <asm/elf.h>
@@ -61,11 +59,10 @@ void arch_cpu_idle(void)
{
if (tlb_type != hypervisor) {
touch_nmi_watchdog();
- local_irq_enable();
} else {
unsigned long pstate;
- local_irq_enable();
+ raw_local_irq_enable();
/* The sun4v sleeping code requires that we have PSTATE.IE cleared over
* the cpu sleep hypervisor call.
@@ -77,8 +74,13 @@ void arch_cpu_idle(void)
: "=&r" (pstate)
: "i" (PSTATE_IE));
- if (!need_resched() && !cpu_is_offline(smp_processor_id()))
+ if (!need_resched() && !cpu_is_offline(smp_processor_id())) {
sun4v_cpu_yield();
+ /* If resumed by cpu_poke then we need to explicitly
+ * call scheduler_ipi().
+ */
+ scheduler_poke();
+ }
/* Re-enable interrupts. */
__asm__ __volatile__(
@@ -87,11 +89,13 @@ void arch_cpu_idle(void)
"wrpr %0, %%g0, %%pstate"
: "=&r" (pstate)
: "i" (PSTATE_IE));
+
+ raw_local_irq_disable();
}
}
#ifdef CONFIG_HOTPLUG_CPU
-void arch_cpu_idle_dead(void)
+void __noreturn arch_cpu_idle_dead(void)
{
sched_preempt_enable_no_resched();
cpu_play_dead();
@@ -103,18 +107,13 @@ static void show_regwindow32(struct pt_regs *regs)
{
struct reg_window32 __user *rw;
struct reg_window32 r_w;
- mm_segment_t old_fs;
__asm__ __volatile__ ("flushw");
rw = compat_ptr((unsigned int)regs->u_regs[14]);
- old_fs = get_fs();
- set_fs (USER_DS);
if (copy_from_user (&r_w, rw, sizeof(r_w))) {
- set_fs (old_fs);
return;
}
- set_fs (old_fs);
printk("l0: %08x l1: %08x l2: %08x l3: %08x "
"l4: %08x l5: %08x l6: %08x l7: %08x\n",
r_w.locals[0], r_w.locals[1], r_w.locals[2], r_w.locals[3],
@@ -133,7 +132,6 @@ static void show_regwindow(struct pt_regs *regs)
struct reg_window __user *rw;
struct reg_window *rwk;
struct reg_window r_w;
- mm_segment_t old_fs;
if ((regs->tstate & TSTATE_PRIV) || !(test_thread_flag(TIF_32BIT))) {
__asm__ __volatile__ ("flushw");
@@ -142,14 +140,10 @@ static void show_regwindow(struct pt_regs *regs)
rwk = (struct reg_window *)
(regs->u_regs[14] + STACK_BIAS);
if (!(regs->tstate & TSTATE_PRIV)) {
- old_fs = get_fs();
- set_fs (USER_DS);
if (copy_from_user (&r_w, rw, sizeof(r_w))) {
- set_fs (old_fs);
return;
}
rwk = &r_w;
- set_fs (old_fs);
}
} else {
show_regwindow32(regs);
@@ -188,7 +182,7 @@ void show_regs(struct pt_regs *regs)
regs->u_regs[15]);
printk("RPC: <%pS>\n", (void *) regs->u_regs[15]);
show_regwindow(regs);
- show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]);
+ show_stack(current, (unsigned long *)regs->u_regs[UREG_FP], KERN_DEFAULT);
}
union global_cpu_snapshot global_cpu_snapshot[NR_CPUS];
@@ -242,7 +236,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp)
}
}
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
{
struct thread_info *tp = current_thread_info();
struct pt_regs *regs = get_irq_regs();
@@ -258,7 +252,7 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
- if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
+ if (cpumask_test_cpu(this_cpu, mask) && this_cpu != exclude_cpu)
__global_reg_self(tp, regs, this_cpu);
smp_fetch_global_regs();
@@ -266,7 +260,7 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
for_each_cpu(cpu, mask) {
struct global_reg_snapshot *gp;
- if (exclude_self && cpu == this_cpu)
+ if (cpu == exclude_cpu)
continue;
gp = &global_cpu_snapshot[cpu].reg;
@@ -301,12 +295,12 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
#ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handle_globreg(int key)
+static void sysrq_handle_globreg(u8 key)
{
trigger_all_cpu_backtrace();
}
-static struct sysrq_key_op sparc_globalreg_op = {
+static const struct sysrq_key_op sparc_globalreg_op = {
.handler = sysrq_handle_globreg,
.help_msg = "global-regs(y)",
.action_msg = "Show Global CPU Regs",
@@ -376,12 +370,12 @@ static void pmu_snapshot_all_cpus(void)
spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags);
}
-static void sysrq_handle_globpmu(int key)
+static void sysrq_handle_globpmu(u8 key)
{
pmu_snapshot_all_cpus();
}
-static struct sysrq_key_op sparc_globalpmu_op = {
+static const struct sysrq_key_op sparc_globalpmu_op = {
.handler = sysrq_handle_globpmu,
.help_msg = "global-pmu(x)",
.action_msg = "Show Global PMU Regs",
@@ -452,7 +446,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
distance = fp - psp;
rval = (csp - distance);
- if (copy_in_user((void __user *) rval, (void __user *) psp, distance))
+ if (raw_copy_in_user((void __user *)rval, (void __user *)psp, distance))
rval = 0;
else if (!stack_64bit) {
if (put_user(((u32)csp),
@@ -512,17 +506,15 @@ void synchronize_user_stack(void)
static void stack_unaligned(unsigned long sp)
{
- siginfo_t info;
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRALN;
- info.si_addr = (void __user *) sp;
- info.si_trapno = 0;
- force_sig_info(SIGBUS, &info, current);
+ force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *) sp);
}
-void fault_in_user_windows(void)
+static const char uwfault32[] = KERN_INFO \
+ "%s[%d]: bad register window fault: SP %08lx (orig_sp %08lx) TPC %08lx O7 %08lx\n";
+static const char uwfault64[] = KERN_INFO \
+ "%s[%d]: bad register window fault: SP %016lx (orig_sp %016lx) TPC %08lx O7 %016lx\n";
+
+void fault_in_user_windows(struct pt_regs *regs)
{
struct thread_info *t = current_thread_info();
unsigned long window;
@@ -535,9 +527,9 @@ void fault_in_user_windows(void)
do {
struct reg_window *rwin = &t->reg_window[window];
int winsize = sizeof(struct reg_window);
- unsigned long sp;
+ unsigned long sp, orig_sp;
- sp = t->rwbuf_stkptrs[window];
+ orig_sp = sp = t->rwbuf_stkptrs[window];
if (test_thread_64bit_stack(sp))
sp += STACK_BIAS;
@@ -548,8 +540,16 @@ void fault_in_user_windows(void)
stack_unaligned(sp);
if (unlikely(copy_to_user((char __user *)sp,
- rwin, winsize)))
+ rwin, winsize))) {
+ if (show_unhandled_signals)
+ printk_ratelimited(is_compat_task() ?
+ uwfault32 : uwfault64,
+ current->comm, current->pid,
+ sp, orig_sp,
+ regs->tpc,
+ regs->u_regs[UREG_I7]);
goto barf;
+ }
} while (window--);
}
set_thread_wsaved(0);
@@ -557,42 +557,7 @@ void fault_in_user_windows(void)
barf:
set_thread_wsaved(window + 1);
- user_exit();
- do_exit(SIGILL);
-}
-
-asmlinkage long sparc_do_fork(unsigned long clone_flags,
- unsigned long stack_start,
- struct pt_regs *regs,
- unsigned long stack_size)
-{
- int __user *parent_tid_ptr, *child_tid_ptr;
- unsigned long orig_i1 = regs->u_regs[UREG_I1];
- long ret;
-
-#ifdef CONFIG_COMPAT
- if (test_thread_flag(TIF_32BIT)) {
- parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]);
- child_tid_ptr = compat_ptr(regs->u_regs[UREG_I4]);
- } else
-#endif
- {
- parent_tid_ptr = (int __user *) regs->u_regs[UREG_I2];
- child_tid_ptr = (int __user *) regs->u_regs[UREG_I4];
- }
-
- ret = do_fork(clone_flags, stack_start, stack_size,
- parent_tid_ptr, child_tid_ptr);
-
- /* If we get an error and potentially restart the system
- * call, we're screwed because copy_thread() clobbered
- * the parent's %o1. So detect that case and restore it
- * here.
- */
- if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
- regs->u_regs[UREG_I1] = orig_i1;
-
- return ret;
+ force_sig(SIGSEGV);
}
/* Copy a Sparc thread. The fork() return value conventions
@@ -600,9 +565,11 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
* Parent --> %o0 == childs pid, %o1 == 0
* Child --> %o0 == parents pid, %o1 == 1
*/
-int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long arg, struct task_struct *p)
+int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
+ u64 clone_flags = args->flags;
+ unsigned long sp = args->stack;
+ unsigned long tls = args->tls;
struct thread_info *t = task_thread_info(p);
struct pt_regs *regs = current_pt_regs();
struct sparc_stackf *parent_sf;
@@ -620,13 +587,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
sizeof(struct sparc_stackf));
t->fpsaved[0] = 0;
- if (unlikely(p->flags & PF_KTHREAD)) {
+ if (unlikely(args->fn)) {
memset(child_trap_frame, 0, child_stack_sz);
__thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
(current_pt_regs()->tstate + 1) & TSTATE_CWP;
- t->current_ds = ASI_P;
- t->kregs->u_regs[UREG_G1] = sp; /* function */
- t->kregs->u_regs[UREG_G2] = arg;
+ t->kregs->u_regs[UREG_G1] = (unsigned long) args->fn;
+ t->kregs->u_regs[UREG_G2] = (unsigned long) args->fn_arg;
return 0;
}
@@ -639,7 +605,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
t->kregs->u_regs[UREG_FP] = sp;
__thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
(regs->tstate + 1) & TSTATE_CWP;
- t->current_ds = ASI_AIUS;
if (sp != regs->u_regs[UREG_FP]) {
unsigned long csp;
@@ -659,78 +624,37 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
regs->u_regs[UREG_I1] = 0;
if (clone_flags & CLONE_SETTLS)
- t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
+ t->kregs->u_regs[UREG_G7] = tls;
return 0;
}
-typedef struct {
- union {
- unsigned int pr_regs[32];
- unsigned long pr_dregs[16];
- } pr_fr;
- unsigned int __unused;
- unsigned int pr_fsr;
- unsigned char pr_qcnt;
- unsigned char pr_q_entrysize;
- unsigned char pr_en;
- unsigned int pr_q[64];
-} elf_fpregset_t32;
-
-/*
- * fill in the fpu structure for a core dump.
+/* TIF_MCDPER in thread info flags for current task is updated lazily upon
+ * a context switch. Update this flag in current task's thread flags
+ * before dup so the dup'd task will inherit the current TIF_MCDPER flag.
*/
-int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- unsigned long *kfpregs = current_thread_info()->fpregs;
- unsigned long fprs = current_thread_info()->fpsaved[0];
+ if (adi_capable()) {
+ register unsigned long tmp_mcdper;
- if (test_thread_flag(TIF_32BIT)) {
- elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
-
- if (fprs & FPRS_DL)
- memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs,
- sizeof(unsigned int) * 32);
- else
- memset(&fpregs32->pr_fr.pr_regs[0], 0,
- sizeof(unsigned int) * 32);
- fpregs32->pr_qcnt = 0;
- fpregs32->pr_q_entrysize = 8;
- memset(&fpregs32->pr_q[0], 0,
- (sizeof(unsigned int) * 64));
- if (fprs & FPRS_FEF) {
- fpregs32->pr_fsr = (unsigned int) current_thread_info()->xfsr[0];
- fpregs32->pr_en = 1;
- } else {
- fpregs32->pr_fsr = 0;
- fpregs32->pr_en = 0;
- }
- } else {
- if(fprs & FPRS_DL)
- memcpy(&fpregs->pr_regs[0], kfpregs,
- sizeof(unsigned int) * 32);
- else
- memset(&fpregs->pr_regs[0], 0,
- sizeof(unsigned int) * 32);
- if(fprs & FPRS_DU)
- memcpy(&fpregs->pr_regs[16], kfpregs+16,
- sizeof(unsigned int) * 32);
+ __asm__ __volatile__(
+ ".word 0x83438000\n\t" /* rd %mcdper, %g1 */
+ "mov %%g1, %0\n\t"
+ : "=r" (tmp_mcdper)
+ :
+ : "g1");
+ if (tmp_mcdper)
+ set_thread_flag(TIF_MCDPER);
else
- memset(&fpregs->pr_regs[16], 0,
- sizeof(unsigned int) * 32);
- if(fprs & FPRS_FEF) {
- fpregs->pr_fsr = current_thread_info()->xfsr[0];
- fpregs->pr_gsr = current_thread_info()->gsr[0];
- } else {
- fpregs->pr_fsr = fpregs->pr_gsr = 0;
- }
- fpregs->pr_fprs = fprs;
+ clear_thread_flag(TIF_MCDPER);
}
- return 1;
+
+ *dst = *src;
+ return 0;
}
-EXPORT_SYMBOL(dump_fpu);
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc, fp, bias = 0;
struct thread_info *tp;
@@ -738,10 +662,6 @@ unsigned long get_wchan(struct task_struct *task)
unsigned long ret = 0;
int count = 0;
- if (!task || task == current ||
- task->state == TASK_RUNNING)
- goto out;
-
tp = task_thread_info(task);
bias = STACK_BIAS;
fp = task_thread_info(task)->ksp + bias;