Release 4.14 arch/powerpc/kernel/process.c
/*
* Derived from "arch/i386/kernel/process.c"
* Copyright (C) 1995 Linus Torvalds
*
* Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
* Paul Mackerras (paulus@cs.anu.edu.au)
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/elf.h>
#include <linux/prctl.h>
#include <linux/init_task.h>
#include <linux/export.h>
#include <linux/kallsyms.h>
#include <linux/mqueue.h>
#include <linux/hardirq.h>
#include <linux/utsname.h>
#include <linux/ftrace.h>
#include <linux/kernel_stat.h>
#include <linux/personality.h>
#include <linux/random.h>
#include <linux/hw_breakpoint.h>
#include <linux/uaccess.h>
#include <linux/elf-randomize.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/time.h>
#include <asm/runlatch.h>
#include <asm/syscalls.h>
#include <asm/switch_to.h>
#include <asm/tm.h>
#include <asm/debug.h>
#ifdef CONFIG_PPC64
#include <asm/firmware.h>
#endif
#include <asm/code-patching.h>
#include <asm/exec.h>
#include <asm/livepatch.h>
#include <asm/cpu_has_feature.h>
#include <asm/asm-prototypes.h>
#include <linux/kprobes.h>
#include <linux/kdebug.h>
/* Transactional Memory debug */
#ifdef TM_DEBUG_SW
#define TM_DEBUG(x...) printk(KERN_INFO x)
#else
#define TM_DEBUG(x...) do { } while(0)
#endif
extern unsigned long _get_SP(void);
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
static void check_if_tm_restore_required(struct task_struct *tsk)
{
/*
* If we are saving the current thread's registers, and the
* thread is in a transactional state, set the TIF_RESTORE_TM
* bit so that we know to restore the registers before
* returning to userspace.
*/
if (tsk == current && tsk->thread.regs &&
MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
!test_thread_flag(TIF_RESTORE_TM)) {
tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr;
set_thread_flag(TIF_RESTORE_TM);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 59 | 92.19% | 1 | 33.33% |
Anshuman Khandual | 3 | 4.69% | 1 | 33.33% |
Anton Blanchard | 2 | 3.12% | 1 | 33.33% |
Total | 64 | 100.00% | 3 | 100.00% |
static inline bool msr_tm_active(unsigned long msr)
{
return MSR_TM_ACTIVE(msr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
#else
static inline bool msr_tm_active(unsigned long msr) { return false; }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 7 | 63.64% | 1 | 50.00% |
Anton Blanchard | 4 | 36.36% | 1 | 50.00% |
Total | 11 | 100.00% | 2 | 100.00% |
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
bool strict_msr_control;
EXPORT_SYMBOL(strict_msr_control);
static int __init enable_strict_msr_control(char *str)
{
strict_msr_control = true;
pr_info("Enabling strict facility control\n");
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 23 | 100.00% | 2 | 100.00% |
Total | 23 | 100.00% | 2 | 100.00% |
early_param("ppc_strict_facility_enable", enable_strict_msr_control);
unsigned long msr_check_and_set(unsigned long bits)
{
unsigned long oldmsr = mfmsr();
unsigned long newmsr;
newmsr = oldmsr | bits;
#ifdef CONFIG_VSX
if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
newmsr |= MSR_VSX;
#endif
if (oldmsr != newmsr)
mtmsr_isync(newmsr);
return newmsr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 58 | 92.06% | 2 | 66.67% |
Cyril Bur | 5 | 7.94% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
void __msr_check_and_clear(unsigned long bits)
{
unsigned long oldmsr = mfmsr();
unsigned long newmsr;
newmsr = oldmsr & ~bits;
#ifdef CONFIG_VSX
if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
newmsr &= ~MSR_VSX;
#endif
if (oldmsr != newmsr)
mtmsr_isync(newmsr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 61 | 100.00% | 3 | 100.00% |
Total | 61 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(__msr_check_and_clear);
#ifdef CONFIG_PPC_FPU
void __giveup_fpu(struct task_struct *tsk)
{
unsigned long msr;
save_fpu(tsk);
msr = tsk->thread.regs->msr;
msr &= ~MSR_FP;
#ifdef CONFIG_VSX
if (cpu_has_feature(CPU_FTR_VSX))
msr &= ~MSR_VSX;
#endif
tsk->thread.regs->msr = msr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 44 | 72.13% | 1 | 50.00% |
Anton Blanchard | 17 | 27.87% | 1 | 50.00% |
Total | 61 | 100.00% | 2 | 100.00% |
void giveup_fpu(struct task_struct *tsk)
{
check_if_tm_restore_required(tsk);
msr_check_and_set(MSR_FP);
__giveup_fpu(tsk);
msr_check_and_clear(MSR_FP);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 30 | 100.00% | 2 | 100.00% |
Total | 30 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(giveup_fpu);
/*
* Make sure the floating-point register state in the
* the thread_struct is up to date for task tsk.
*/
void flush_fp_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
/*
* We need to disable preemption here because if we didn't,
* another process could get scheduled after the regs->msr
* test but before we have finished saving the FP registers
* to the thread_struct. That process could take over the
* FPU, and then when we get scheduled again we would store
* bogus values for the remaining FP registers.
*/
preempt_disable();
if (tsk->thread.regs->msr & MSR_FP) {
/*
* This should only ever be called for current or
* for a stopped child process. Since we save away
* the FP register state on context switch,
* there is something wrong if a stopped child appears
* to still have its FP state in the CPU registers.
*/
BUG_ON(tsk != current);
giveup_fpu(tsk);
}
preempt_enable();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 51 | 94.44% | 1 | 25.00% |
Anton Blanchard | 2 | 3.70% | 2 | 50.00% |
Kumar Gala | 1 | 1.85% | 1 | 25.00% |
Total | 54 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(flush_fp_to_thread);
void enable_kernel_fp(void)
{
unsigned long cpumsr;
WARN_ON(preemptible());
cpumsr = msr_check_and_set(MSR_FP);
if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) {
check_if_tm_restore_required(current);
/*
* If a thread has already been reclaimed then the
* checkpointed registers are on the CPU but have definitely
* been saved by the reclaim code. Don't need to and *cannot*
* giveup as this would save to the 'live' structure not the
* checkpointed structure.
*/
if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
return;
__giveup_fpu(current);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 36 | 46.75% | 1 | 20.00% |
Cyril Bur | 27 | 35.06% | 1 | 20.00% |
Anton Blanchard | 14 | 18.18% | 3 | 60.00% |
Total | 77 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(enable_kernel_fp);
static int restore_fp(struct task_struct *tsk)
{
if (tsk->thread.load_fp || msr_tm_active(tsk->thread.regs->msr)) {
load_fp_state(¤t->thread.fp_state);
current->thread.load_fp++;
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 55 | 100.00% | 2 | 100.00% |
Total | 55 | 100.00% | 2 | 100.00% |
#else
static int restore_fp(struct task_struct *tsk) { return 0; }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
#endif /* CONFIG_PPC_FPU */
#ifdef CONFIG_ALTIVEC
#define loadvec(thr) ((thr).load_vec)
static void __giveup_altivec(struct task_struct *tsk)
{
unsigned long msr;
save_altivec(tsk);
msr = tsk->thread.regs->msr;
msr &= ~MSR_VEC;
#ifdef CONFIG_VSX
if (cpu_has_feature(CPU_FTR_VSX))
msr &= ~MSR_VSX;
#endif
tsk->thread.regs->msr = msr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 45 | 72.58% | 1 | 50.00% |
Anton Blanchard | 17 | 27.42% | 1 | 50.00% |
Total | 62 | 100.00% | 2 | 100.00% |
void giveup_altivec(struct task_struct *tsk)
{
check_if_tm_restore_required(tsk);
msr_check_and_set(MSR_VEC);
__giveup_altivec(tsk);
msr_check_and_clear(MSR_VEC);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 30 | 100.00% | 2 | 100.00% |
Total | 30 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(giveup_altivec);
void enable_kernel_altivec(void)
{
unsigned long cpumsr;
WARN_ON(preemptible());
cpumsr = msr_check_and_set(MSR_VEC);
if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) {
check_if_tm_restore_required(current);
/*
* If a thread has already been reclaimed then the
* checkpointed registers are on the CPU but have definitely
* been saved by the reclaim code. Don't need to and *cannot*
* giveup as this would save to the 'live' structure not the
* checkpointed structure.
*/
if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
return;
__giveup_altivec(current);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 32 | 41.56% | 1 | 20.00% |
Cyril Bur | 27 | 35.06% | 1 | 20.00% |
Anton Blanchard | 18 | 23.38% | 3 | 60.00% |
Total | 77 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(enable_kernel_altivec);
/*
* Make sure the VMX/Altivec register state in the
* the thread_struct is up to date for task tsk.
*/
void flush_altivec_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & MSR_VEC) {
BUG_ON(tsk != current);
giveup_altivec(tsk);
}
preempt_enable();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 50 | 96.15% | 1 | 33.33% |
Anton Blanchard | 1 | 1.92% | 1 | 33.33% |
Kumar Gala | 1 | 1.92% | 1 | 33.33% |
Total | 52 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
static int restore_altivec(struct task_struct *tsk)
{
if (cpu_has_feature(CPU_FTR_ALTIVEC) &&
(tsk->thread.load_vec || msr_tm_active(tsk->thread.regs->msr))) {
load_vr_state(&tsk->thread.vr_state);
tsk->thread.used_vr = 1;
tsk->thread.load_vec++;
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 45 | 64.29% | 2 | 66.67% |
Anton Blanchard | 25 | 35.71% | 1 | 33.33% |
Total | 70 | 100.00% | 3 | 100.00% |
#else
#define loadvec(thr) 0
static inline int restore_altivec(struct task_struct *tsk) { return 0; }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 15 | 100.00% | 1 | 100.00% |
Total | 15 | 100.00% | 1 | 100.00% |
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_VSX
static void __giveup_vsx(struct task_struct *tsk)
{
unsigned long msr = tsk->thread.regs->msr;
/*
* We should never be ssetting MSR_VSX without also setting
* MSR_FP and MSR_VEC
*/
WARN_ON((msr & MSR_VSX) && !((msr & MSR_FP) && (msr & MSR_VEC)));
/* __giveup_fpu will clear MSR_VSX */
if (msr & MSR_FP)
__giveup_fpu(tsk);
if (msr & MSR_VEC)
__giveup_altivec(tsk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 35 | 49.30% | 2 | 50.00% |
Benjamin Herrenschmidt | 34 | 47.89% | 1 | 25.00% |
Cyril Bur | 2 | 2.82% | 1 | 25.00% |
Total | 71 | 100.00% | 4 | 100.00% |
static void giveup_vsx(struct task_struct *tsk)
{
check_if_tm_restore_required(tsk);
msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
__giveup_vsx(tsk);
msr_check_and_clear(MSR_FP|MSR_VEC|MSR_VSX);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 21 | 53.85% | 1 | 33.33% |
Anton Blanchard | 18 | 46.15% | 2 | 66.67% |
Total | 39 | 100.00% | 3 | 100.00% |
void enable_kernel_vsx(void)
{
unsigned long cpumsr;
WARN_ON(preemptible());
cpumsr = msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
if (current->thread.regs &&
(current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP))) {
check_if_tm_restore_required(current);
/*
* If a thread has already been reclaimed then the
* checkpointed registers are on the CPU but have definitely
* been saved by the reclaim code. Don't need to and *cannot*
* giveup as this would save to the 'live' structure not the
* checkpointed structure.
*/
if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
return;
__giveup_vsx(current);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Leonidas Da Silva Barbosa | 35 | 40.23% | 1 | 16.67% |
Cyril Bur | 27 | 31.03% | 1 | 16.67% |
Anton Blanchard | 19 | 21.84% | 3 | 50.00% |
Benjamin Herrenschmidt | 6 | 6.90% | 1 | 16.67% |
Total | 87 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL(enable_kernel_vsx);
void flush_vsx_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
BUG_ON(tsk != current);
giveup_vsx(tsk);
}
preempt_enable();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Michael Neuling | 52 | 89.66% | 1 | 50.00% |
Benjamin Herrenschmidt | 6 | 10.34% | 1 | 50.00% |
Total | 58 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(flush_vsx_to_thread);
static int restore_vsx(struct task_struct *tsk)
{
if (cpu_has_feature(CPU_FTR_VSX)) {
tsk->thread.used_vsr = 1;
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 34 | 100.00% | 1 | 100.00% |
Total | 34 | 100.00% | 1 | 100.00% |
#else
static inline int restore_vsx(struct task_struct *tsk) { return 0; }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 15 | 100.00% | 1 | 100.00% |
Total | 15 | 100.00% | 1 | 100.00% |
#endif /* CONFIG_VSX */
#ifdef CONFIG_SPE
void giveup_spe(struct task_struct *tsk)
{
check_if_tm_restore_required(tsk);
msr_check_and_set(MSR_SPE);
__giveup_spe(tsk);
msr_check_and_clear(MSR_SPE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 30 | 100.00% | 2 | 100.00% |
Total | 30 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(giveup_spe);
void enable_kernel_spe(void)
{
WARN_ON(preemptible());
msr_check_and_set(MSR_SPE);
if (current->thread.regs && (current->thread.regs->msr & MSR_SPE)) {
check_if_tm_restore_required(current);
__giveup_spe(current);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 36 | 72.00% | 1 | 25.00% |
Anton Blanchard | 14 | 28.00% | 3 | 75.00% |
Total | 50 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(enable_kernel_spe);
void flush_spe_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & MSR_SPE) {
BUG_ON(tsk != current);
tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
giveup_spe(tsk);
}
preempt_enable();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 51 | 80.95% | 1 | 33.33% |
Liu Yu | 11 | 17.46% | 1 | 33.33% |
Kumar Gala | 1 | 1.59% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
#endif /* CONFIG_SPE */
static unsigned long msr_all_available;
static int __init init_msr_all_available(void)
{
#ifdef CONFIG_PPC_FPU
msr_all_available |= MSR_FP;
#endif
#ifdef CONFIG_ALTIVEC
if (cpu_has_feature(CPU_FTR_ALTIVEC))
msr_all_available |= MSR_VEC;
#endif
#ifdef CONFIG_VSX
if (cpu_has_feature(CPU_FTR_VSX))
msr_all_available |= MSR_VSX;
#endif
#ifdef CONFIG_SPE
if (cpu_has_feature(CPU_FTR_SPE))
msr_all_available |= MSR_SPE;
#endif
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 69 | 100.00% | 1 | 100.00% |
Total | 69 | 100.00% | 1 | 100.00% |
early_initcall(init_msr_all_available);
void giveup_all(struct task_struct *tsk)
{
unsigned long usermsr;
if (!tsk->thread.regs)
return;
usermsr = tsk->thread.regs->msr;
if ((usermsr & msr_all_available) == 0)
return;
msr_check_and_set(msr_all_available);
check_if_tm_restore_required(tsk);
WARN_ON((usermsr & MSR_VSX) && !((usermsr & MSR_FP) && (usermsr & MSR_VEC)));
#ifdef CONFIG_PPC_FPU
if (usermsr & MSR_FP)
__giveup_fpu(tsk);
#endif
#ifdef CONFIG_ALTIVEC
if (usermsr & MSR_VEC)
__giveup_altivec(tsk);
#endif
#ifdef CONFIG_SPE
if (usermsr & MSR_SPE)
__giveup_spe(tsk);
#endif
msr_check_and_clear(msr_all_available);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 103 | 78.03% | 1 | 33.33% |
Benjamin Herrenschmidt | 24 | 18.18% | 1 | 33.33% |
Cyril Bur | 5 | 3.79% | 1 | 33.33% |
Total | 132 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(giveup_all);
void restore_math(struct pt_regs *regs)
{
unsigned long msr;
if (!msr_tm_active(regs->msr) &&
!current->thread.load_fp && !loadvec(current->thread))
return;
msr = regs->msr;
msr_check_and_set(msr_all_available);
/*
* Only reload if the bit is not set in the user MSR, the bit BEING set
* indicates that the registers are hot
*/
if ((!(msr & MSR_FP)) && restore_fp(current))
msr |= MSR_FP | current->thread.fpexc_mode;
if ((!(msr & MSR_VEC)) && restore_altivec(current))
msr |= MSR_VEC;
if ((msr & (MSR_FP | MSR_VEC)) == (MSR_FP | MSR_VEC) &&
restore_vsx(current)) {
msr |= MSR_VSX;
}
msr_check_and_clear(msr_all_available);
regs->msr = msr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cyril Bur | 112 | 81.16% | 2 | 66.67% |
Anton Blanchard | 26 | 18.84% | 1 | 33.33% |
Total | 138 | 100.00% | 3 | 100.00% |
void save_all(struct task_struct *tsk)
{
unsigned long usermsr;
if (!tsk->thread.regs)
return;
usermsr = tsk->thread.regs->msr;
if ((usermsr & msr_all_available) == 0)
return;
msr_check_and_set(msr_all_available);
WARN_ON((usermsr & MSR_VSX) && !((usermsr & MSR_FP) && (usermsr & MSR_VEC)));
if (usermsr & MSR_FP)
save_fpu(tsk);
if (usermsr & MSR_VEC)
save_altivec(tsk);
if (usermsr & MSR_SPE)
__giveup_spe(tsk);
msr_check_and_clear(msr_all_available);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 87 | 77.68% | 1 | 25.00% |
Benjamin Herrenschmidt | 19 | 16.96% | 1 | 25.00% |
Cyril Bur | 6 | 5.36% | 2 | 50.00% |
Total | 112 | 100.00% | 4 | 100.00% |
void flush_all_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
preempt_disable();
BUG_ON(tsk != current);
save_all(tsk);
#ifdef CONFIG_SPE
if (tsk->thread.regs->msr & MSR_SPE)
tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
#endif
preempt_enable();
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 65 | 98.48% | 1 | 50.00% |
Cyril Bur | 1 | 1.52% | 1 | 50.00% |
Total | 66 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(flush_all_to_thread);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
void do_send_trap(struct pt_regs *regs, unsigned long address,
unsigned long error_code, int signal_code, int breakpt)
{
siginfo_t info;
current->thread.trap_nr = signal_code;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;
/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
info.si_errno = breakpt; /* breakpoint or watchpoint id */
info.si_code = signal_code;
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Kleikamp | 88 | 91.67% | 1 | 50.00% |
Ananth N. Mavinakayanahalli | 8 | 8.33% | 1 | 50.00% |
Total | 96 | 100.00% | 2 | 100.00% |
#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
void do_break (struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
siginfo_t info;
current->thread.trap_nr = TRAP_HWBKPT;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;
if (debugger_break_match(regs))
return;
/* Clear the breakpoint */
hw_breakpoint_disable();
/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_HWBKPT;
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Machado | 88 | 87.13% | 1 | 33.33% |
Ananth N. Mavinakayanahalli | 8 | 7.92% | 1 | 33.33% |
Michael Neuling | 5 | 4.95% | 1 | 33.33% |
Total | 101 | 100.00% | 3 | 100.00% |
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
/*
* Set the debug registers back to their default "safe" values.
*/
static void set_debug_reg_defaults(struct thread_struct *thread)
{
thread->debug.iac1 = thread->debug.iac2 = 0;
#if CONFIG_PPC_ADV_DEBUG_IACS > 2
thread->debug.iac3 = thread->debug.iac4 = 0;
#endif
thread->debug.dac1 = thread->debug.dac2 = 0;
#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
thread->debug.dvc1 = thread->debug.dvc2 = 0;
#endif
thread->debug.dbcr0 = 0;
#ifdef CONFIG_BOOKE
/*
* Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
*/
thread->debug.dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
DBCR1_IAC3US | DBCR1_IAC4US;
/*
* Force Data Address Compare User/Supervisor bits to be User-only
* (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0.
*/
thread->debug.dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
#else
thread->debug.dbcr1 = 0;
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Kleikamp | 106 | 81.54% | 1 | 50.00% |
Bharat Bhushan | 24 | 18.46% | 1 | 50.00% |
Total | 130 | 100.00% | 2 | 100.00% |
static void prime_debug_regs(struct debug_reg *debug)
{
/*
* We could have inherited MSR_DE from userspace, since
* it doesn't get cleared on exception entry. Make sure
* MSR_DE is clear before we enable any debug events.
*/
mtmsr(mfmsr() & ~MSR_DE);
mtspr(SPRN_IAC1, debug->iac1);
mtspr(SPRN_IAC2, debug->iac2);
#if CONFIG_PPC_ADV_DEBUG_IACS > 2
mtspr(SPRN_IAC3, debug->iac3);
mtspr(SPRN_IAC4, debug->iac4);
#endif
mtspr(SPRN_DAC1, debug->dac1);
mtspr(SPRN_DAC2, debug->dac2);
#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
mtspr(SPRN_DVC1, debug->dvc1);
mtspr(SPRN_DVC2, debug->dvc2);
#endif
mtspr(SPRN_DBCR0, debug->dbcr0);
mtspr(SPRN_DBCR1, debug->dbcr1);
#ifdef CONFIG_BOOKE
mtspr(SPRN_DBCR2, debug->dbcr2);
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Kleikamp | 105 | 75.54% | 1 | 25.00% |
Scott Wood | 23 | 16.55% | 2 | 50.00% |
Bharat Bhushan | 11 | 7.91% | 1 | 25.00% |
Total | 139 | 100.00% | 4 | 100.00% |
/*
* Unless neither the old or new thread are making use of the
* debug registers, set the debug registers from the values
* stored in the new thread.
*/
void switch_booke_debug_regs(struct debug_reg *new_debug)
{
if ((current->thread.debug.dbcr0 & DBCR0_IDM)
|| (new_debug->dbcr0 & DBCR0_IDM))
prime_debug_regs(new_debug);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Kleikamp | 31 | 83.78% | 1 | 33.33% |
Scott Wood | 4 | 10.81% | 1 | 33.33% |
Bharat Bhushan | 2 | 5.41% | 1 | 33.33% |
Total | 37 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(switch_booke_debug_regs);
#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
#ifndef CONFIG_HAVE_HW_BREAKPOINT
static void set_debug_reg_defaults(struct thread_struct *thread)
{
thread->hw_brk.address = 0;
thread->hw_brk.type = 0;
set_breakpoint(&thread->hw_brk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Kleikamp | 19 | 54.29% | 1 | 25.00% |
Michael Neuling | 16 | 45.71% | 3 | 75.00% |
Total | 35 | 100.00% | 4 | 100.00% |
#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
{
mtspr(SPRN_DAC1, dabr);
#ifdef CONFIG_PPC_47x
isync();
#endif
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 11 | 33.33% | 1 | 16.67% |
Michael Neuling | 11 | 33.33% | 2 | 33.33% |
Dave Kleikamp | 8 | 24.24% | 1 | 16.67% |
Michael Ellerman | 2 | 6.06% | 1 | 16.67% |
Benjamin Herrenschmidt | 1 | 3.03% | 1 | 16.67% |
Total | 33 | 100.00% | 6 | 100.00% |
#elif defined(CONFIG_PPC_BOOK3S)
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
{
mtspr(SPRN_DABR, dabr);
if (cpu_has_feature(CPU_FTR_DABRX))
mtspr(SPRN_DABRX, dabrx);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Michael Neuling | 32 | 82.05% | 3 | 60.00% |
Luis Machado | 6 | 15.38% | 1 | 20.00% |
Benjamin Herrenschmidt | 1 | 2.56% | 1 | 20.00% |
Total | 39 | 100.00% | 5 | 100.00% |
#elif defined(CONFIG_PPC_8xx)
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
{
unsigned long addr = dabr & ~HW_BRK_TYPE_DABR;
unsigned long lctrl1 = 0x90000000; /* compare type: equal on E & F */
unsigned long lctrl2 = 0x8e000002; /* watchpoint 1 on cmp E | F */
if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_READ)
lctrl1 |= 0xa0000;
else if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_WRITE)
lctrl1 |= 0xf0000;
else if ((dabr & HW_BRK_TYPE_RDWR) == 0)
lctrl2 = 0;
mtspr(