Merge commit '517ffce4e1a03aea979fe3a18a3dd1761a24fafb' into arch-sparc
Backmerge from the point in mainline where a trivial conflict had been introduced (arch/sparc/kernel/sys_sparc_64.c had grown sys_kern_features() right after where kernel_execve() used to be) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
@@ -817,15 +817,17 @@ static u64 nop_for_index(int idx)
|
||||
|
||||
static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
|
||||
{
|
||||
u64 val, mask = mask_for_index(idx);
|
||||
u64 enc, val, mask = mask_for_index(idx);
|
||||
int pcr_index = 0;
|
||||
|
||||
if (sparc_pmu->num_pcrs > 1)
|
||||
pcr_index = idx;
|
||||
|
||||
enc = perf_event_get_enc(cpuc->events[idx]);
|
||||
|
||||
val = cpuc->pcr[pcr_index];
|
||||
val &= ~mask;
|
||||
val |= hwc->config;
|
||||
val |= event_encoding(enc, idx);
|
||||
cpuc->pcr[pcr_index] = val;
|
||||
|
||||
pcr_ops->write_pcr(pcr_index, cpuc->pcr[pcr_index]);
|
||||
@@ -1738,8 +1740,6 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry,
|
||||
{
|
||||
unsigned long ufp;
|
||||
|
||||
perf_callchain_store(entry, regs->tpc);
|
||||
|
||||
ufp = regs->u_regs[UREG_I6] + STACK_BIAS;
|
||||
do {
|
||||
struct sparc_stackf *usf, sf;
|
||||
@@ -1760,19 +1760,27 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
|
||||
{
|
||||
unsigned long ufp;
|
||||
|
||||
perf_callchain_store(entry, regs->tpc);
|
||||
|
||||
ufp = regs->u_regs[UREG_I6] & 0xffffffffUL;
|
||||
do {
|
||||
struct sparc_stackf32 *usf, sf;
|
||||
unsigned long pc;
|
||||
|
||||
usf = (struct sparc_stackf32 *) ufp;
|
||||
if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
|
||||
break;
|
||||
if (thread32_stack_is_64bit(ufp)) {
|
||||
struct sparc_stackf *usf, sf;
|
||||
|
||||
pc = sf.callers_pc;
|
||||
ufp = (unsigned long)sf.fp;
|
||||
ufp += STACK_BIAS;
|
||||
usf = (struct sparc_stackf *) ufp;
|
||||
if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
|
||||
break;
|
||||
pc = sf.callers_pc & 0xffffffff;
|
||||
ufp = ((unsigned long) sf.fp) & 0xffffffff;
|
||||
} else {
|
||||
struct sparc_stackf32 *usf, sf;
|
||||
usf = (struct sparc_stackf32 *) ufp;
|
||||
if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
|
||||
break;
|
||||
pc = sf.callers_pc;
|
||||
ufp = (unsigned long)sf.fp;
|
||||
}
|
||||
perf_callchain_store(entry, pc);
|
||||
} while (entry->nr < PERF_MAX_STACK_DEPTH);
|
||||
}
|
||||
@@ -1780,6 +1788,11 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
|
||||
void
|
||||
perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
{
|
||||
perf_callchain_store(entry, regs->tpc);
|
||||
|
||||
if (!current->mm)
|
||||
return;
|
||||
|
||||
flushw_user();
|
||||
if (test_thread_flag(TIF_32BIT))
|
||||
perf_callchain_user_32(entry, regs);
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <linux/tick.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/elfcore.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/nmi.h>
|
||||
@@ -47,6 +48,7 @@
|
||||
#include <asm/syscalls.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/pcr.h>
|
||||
|
||||
#include "kstack.h"
|
||||
|
||||
@@ -204,18 +206,22 @@ void show_regs(struct pt_regs *regs)
|
||||
show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]);
|
||||
}
|
||||
|
||||
struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
|
||||
static DEFINE_SPINLOCK(global_reg_snapshot_lock);
|
||||
union global_cpu_snapshot global_cpu_snapshot[NR_CPUS];
|
||||
static DEFINE_SPINLOCK(global_cpu_snapshot_lock);
|
||||
|
||||
static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
|
||||
int this_cpu)
|
||||
{
|
||||
struct global_reg_snapshot *rp;
|
||||
|
||||
flushw_all();
|
||||
|
||||
global_reg_snapshot[this_cpu].tstate = regs->tstate;
|
||||
global_reg_snapshot[this_cpu].tpc = regs->tpc;
|
||||
global_reg_snapshot[this_cpu].tnpc = regs->tnpc;
|
||||
global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
|
||||
rp = &global_cpu_snapshot[this_cpu].reg;
|
||||
|
||||
rp->tstate = regs->tstate;
|
||||
rp->tpc = regs->tpc;
|
||||
rp->tnpc = regs->tnpc;
|
||||
rp->o7 = regs->u_regs[UREG_I7];
|
||||
|
||||
if (regs->tstate & TSTATE_PRIV) {
|
||||
struct reg_window *rw;
|
||||
@@ -223,17 +229,17 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
|
||||
rw = (struct reg_window *)
|
||||
(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
if (kstack_valid(tp, (unsigned long) rw)) {
|
||||
global_reg_snapshot[this_cpu].i7 = rw->ins[7];
|
||||
rp->i7 = rw->ins[7];
|
||||
rw = (struct reg_window *)
|
||||
(rw->ins[6] + STACK_BIAS);
|
||||
if (kstack_valid(tp, (unsigned long) rw))
|
||||
global_reg_snapshot[this_cpu].rpc = rw->ins[7];
|
||||
rp->rpc = rw->ins[7];
|
||||
}
|
||||
} else {
|
||||
global_reg_snapshot[this_cpu].i7 = 0;
|
||||
global_reg_snapshot[this_cpu].rpc = 0;
|
||||
rp->i7 = 0;
|
||||
rp->rpc = 0;
|
||||
}
|
||||
global_reg_snapshot[this_cpu].thread = tp;
|
||||
rp->thread = tp;
|
||||
}
|
||||
|
||||
/* In order to avoid hangs we do not try to synchronize with the
|
||||
@@ -261,9 +267,9 @@ void arch_trigger_all_cpu_backtrace(void)
|
||||
if (!regs)
|
||||
regs = tp->kregs;
|
||||
|
||||
spin_lock_irqsave(&global_reg_snapshot_lock, flags);
|
||||
spin_lock_irqsave(&global_cpu_snapshot_lock, flags);
|
||||
|
||||
memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
|
||||
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
|
||||
|
||||
this_cpu = raw_smp_processor_id();
|
||||
|
||||
@@ -272,7 +278,7 @@ void arch_trigger_all_cpu_backtrace(void)
|
||||
smp_fetch_global_regs();
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
|
||||
struct global_reg_snapshot *gp = &global_cpu_snapshot[cpu].reg;
|
||||
|
||||
__global_reg_poll(gp);
|
||||
|
||||
@@ -295,9 +301,9 @@ void arch_trigger_all_cpu_backtrace(void)
|
||||
}
|
||||
}
|
||||
|
||||
memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
|
||||
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
|
||||
|
||||
spin_unlock_irqrestore(&global_reg_snapshot_lock, flags);
|
||||
spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
@@ -309,16 +315,90 @@ static void sysrq_handle_globreg(int key)
|
||||
|
||||
static struct sysrq_key_op sparc_globalreg_op = {
|
||||
.handler = sysrq_handle_globreg,
|
||||
.help_msg = "Globalregs",
|
||||
.help_msg = "global-regs(Y)",
|
||||
.action_msg = "Show Global CPU Regs",
|
||||
};
|
||||
|
||||
static int __init sparc_globreg_init(void)
|
||||
static void __global_pmu_self(int this_cpu)
|
||||
{
|
||||
return register_sysrq_key('y', &sparc_globalreg_op);
|
||||
struct global_pmu_snapshot *pp;
|
||||
int i, num;
|
||||
|
||||
pp = &global_cpu_snapshot[this_cpu].pmu;
|
||||
|
||||
num = 1;
|
||||
if (tlb_type == hypervisor &&
|
||||
sun4v_chip_type >= SUN4V_CHIP_NIAGARA4)
|
||||
num = 4;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
pp->pcr[i] = pcr_ops->read_pcr(i);
|
||||
pp->pic[i] = pcr_ops->read_pic(i);
|
||||
}
|
||||
}
|
||||
|
||||
core_initcall(sparc_globreg_init);
|
||||
static void __global_pmu_poll(struct global_pmu_snapshot *pp)
|
||||
{
|
||||
int limit = 0;
|
||||
|
||||
while (!pp->pcr[0] && ++limit < 100) {
|
||||
barrier();
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void pmu_snapshot_all_cpus(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int this_cpu, cpu;
|
||||
|
||||
spin_lock_irqsave(&global_cpu_snapshot_lock, flags);
|
||||
|
||||
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
|
||||
|
||||
this_cpu = raw_smp_processor_id();
|
||||
|
||||
__global_pmu_self(this_cpu);
|
||||
|
||||
smp_fetch_global_pmu();
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct global_pmu_snapshot *pp = &global_cpu_snapshot[cpu].pmu;
|
||||
|
||||
__global_pmu_poll(pp);
|
||||
|
||||
printk("%c CPU[%3d]: PCR[%08lx:%08lx:%08lx:%08lx] PIC[%08lx:%08lx:%08lx:%08lx]\n",
|
||||
(cpu == this_cpu ? '*' : ' '), cpu,
|
||||
pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3],
|
||||
pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]);
|
||||
}
|
||||
|
||||
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
|
||||
|
||||
spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags);
|
||||
}
|
||||
|
||||
static void sysrq_handle_globpmu(int key)
|
||||
{
|
||||
pmu_snapshot_all_cpus();
|
||||
}
|
||||
|
||||
static struct sysrq_key_op sparc_globalpmu_op = {
|
||||
.handler = sysrq_handle_globpmu,
|
||||
.help_msg = "global-pmu(X)",
|
||||
.action_msg = "Show Global PMU Regs",
|
||||
};
|
||||
|
||||
static int __init sparc_sysrq_init(void)
|
||||
{
|
||||
int ret = register_sysrq_key('y', &sparc_globalreg_op);
|
||||
|
||||
if (!ret)
|
||||
ret = register_sysrq_key('x', &sparc_globalpmu_op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
core_initcall(sparc_sysrq_init);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -372,13 +452,16 @@ void flush_thread(void)
|
||||
/* It's a bit more tricky when 64-bit tasks are involved... */
|
||||
static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
|
||||
{
|
||||
bool stack_64bit = test_thread_64bit_stack(psp);
|
||||
unsigned long fp, distance, rval;
|
||||
|
||||
if (!(test_thread_flag(TIF_32BIT))) {
|
||||
if (stack_64bit) {
|
||||
csp += STACK_BIAS;
|
||||
psp += STACK_BIAS;
|
||||
__get_user(fp, &(((struct reg_window __user *)psp)->ins[6]));
|
||||
fp += STACK_BIAS;
|
||||
if (test_thread_flag(TIF_32BIT))
|
||||
fp &= 0xffffffff;
|
||||
} else
|
||||
__get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6]));
|
||||
|
||||
@@ -392,7 +475,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
|
||||
rval = (csp - distance);
|
||||
if (copy_in_user((void __user *) rval, (void __user *) psp, distance))
|
||||
rval = 0;
|
||||
else if (test_thread_flag(TIF_32BIT)) {
|
||||
else if (!stack_64bit) {
|
||||
if (put_user(((u32)csp),
|
||||
&(((struct reg_window32 __user *)rval)->ins[6])))
|
||||
rval = 0;
|
||||
@@ -427,18 +510,18 @@ void synchronize_user_stack(void)
|
||||
|
||||
flush_user_windows();
|
||||
if ((window = get_thread_wsaved()) != 0) {
|
||||
int winsize = sizeof(struct reg_window);
|
||||
int bias = 0;
|
||||
|
||||
if (test_thread_flag(TIF_32BIT))
|
||||
winsize = sizeof(struct reg_window32);
|
||||
else
|
||||
bias = STACK_BIAS;
|
||||
|
||||
window -= 1;
|
||||
do {
|
||||
unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
|
||||
struct reg_window *rwin = &t->reg_window[window];
|
||||
int winsize = sizeof(struct reg_window);
|
||||
unsigned long sp;
|
||||
|
||||
sp = t->rwbuf_stkptrs[window];
|
||||
|
||||
if (test_thread_64bit_stack(sp))
|
||||
sp += STACK_BIAS;
|
||||
else
|
||||
winsize = sizeof(struct reg_window32);
|
||||
|
||||
if (!copy_to_user((char __user *)sp, rwin, winsize)) {
|
||||
shift_window_buffer(window, get_thread_wsaved() - 1, t);
|
||||
@@ -464,13 +547,6 @@ void fault_in_user_windows(void)
|
||||
{
|
||||
struct thread_info *t = current_thread_info();
|
||||
unsigned long window;
|
||||
int winsize = sizeof(struct reg_window);
|
||||
int bias = 0;
|
||||
|
||||
if (test_thread_flag(TIF_32BIT))
|
||||
winsize = sizeof(struct reg_window32);
|
||||
else
|
||||
bias = STACK_BIAS;
|
||||
|
||||
flush_user_windows();
|
||||
window = get_thread_wsaved();
|
||||
@@ -478,8 +554,16 @@ void fault_in_user_windows(void)
|
||||
if (likely(window != 0)) {
|
||||
window -= 1;
|
||||
do {
|
||||
unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
|
||||
struct reg_window *rwin = &t->reg_window[window];
|
||||
int winsize = sizeof(struct reg_window);
|
||||
unsigned long sp;
|
||||
|
||||
sp = t->rwbuf_stkptrs[window];
|
||||
|
||||
if (test_thread_64bit_stack(sp))
|
||||
sp += STACK_BIAS;
|
||||
else
|
||||
winsize = sizeof(struct reg_window32);
|
||||
|
||||
if (unlikely(sp & 0x7UL))
|
||||
stack_unaligned(sp);
|
||||
|
@@ -151,7 +151,7 @@ static int regwindow64_get(struct task_struct *target,
|
||||
{
|
||||
unsigned long rw_addr = regs->u_regs[UREG_I6];
|
||||
|
||||
if (test_tsk_thread_flag(current, TIF_32BIT)) {
|
||||
if (!test_thread_64bit_stack(rw_addr)) {
|
||||
struct reg_window32 win32;
|
||||
int i;
|
||||
|
||||
@@ -176,7 +176,7 @@ static int regwindow64_set(struct task_struct *target,
|
||||
{
|
||||
unsigned long rw_addr = regs->u_regs[UREG_I6];
|
||||
|
||||
if (test_tsk_thread_flag(current, TIF_32BIT)) {
|
||||
if (!test_thread_64bit_stack(rw_addr)) {
|
||||
struct reg_window32 win32;
|
||||
int i;
|
||||
|
||||
|
@@ -852,6 +852,8 @@ extern unsigned long xcall_flush_tlb_mm;
|
||||
extern unsigned long xcall_flush_tlb_pending;
|
||||
extern unsigned long xcall_flush_tlb_kernel_range;
|
||||
extern unsigned long xcall_fetch_glob_regs;
|
||||
extern unsigned long xcall_fetch_glob_pmu;
|
||||
extern unsigned long xcall_fetch_glob_pmu_n4;
|
||||
extern unsigned long xcall_receive_signal;
|
||||
extern unsigned long xcall_new_mmu_context_version;
|
||||
#ifdef CONFIG_KGDB
|
||||
@@ -1000,6 +1002,15 @@ void smp_fetch_global_regs(void)
|
||||
smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0);
|
||||
}
|
||||
|
||||
void smp_fetch_global_pmu(void)
|
||||
{
|
||||
if (tlb_type == hypervisor &&
|
||||
sun4v_chip_type >= SUN4V_CHIP_NIAGARA4)
|
||||
smp_cross_call(&xcall_fetch_glob_pmu_n4, 0, 0, 0);
|
||||
else
|
||||
smp_cross_call(&xcall_fetch_glob_pmu, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* We know that the window frames of the user have been flushed
|
||||
* to the stack before we get here because all callers of us
|
||||
* are flush_tlb_*() routines, and these run after flush_cache_*()
|
||||
|
@@ -729,3 +729,8 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage long sys_kern_features(void)
|
||||
{
|
||||
return KERN_FEATURE_MIXED_MODE_STACK;
|
||||
}
|
||||
|
@@ -86,6 +86,7 @@ sys_call_table32:
|
||||
.word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
|
||||
/*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
|
||||
.word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
|
||||
/*340*/ .word sys_kern_features
|
||||
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
@@ -163,3 +164,4 @@ sys_call_table:
|
||||
.word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
|
||||
/*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
|
||||
.word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
|
||||
/*340*/ .word sys_kern_features
|
||||
|
@@ -113,21 +113,24 @@ static inline long sign_extend_imm13(long imm)
|
||||
|
||||
static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long value;
|
||||
unsigned long value, fp;
|
||||
|
||||
if (reg < 16)
|
||||
return (!reg ? 0 : regs->u_regs[reg]);
|
||||
|
||||
fp = regs->u_regs[UREG_FP];
|
||||
|
||||
if (regs->tstate & TSTATE_PRIV) {
|
||||
struct reg_window *win;
|
||||
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window *)(fp + STACK_BIAS);
|
||||
value = win->locals[reg - 16];
|
||||
} else if (test_thread_flag(TIF_32BIT)) {
|
||||
} else if (!test_thread_64bit_stack(fp)) {
|
||||
struct reg_window32 __user *win32;
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
|
||||
get_user(value, &win32->locals[reg - 16]);
|
||||
} else {
|
||||
struct reg_window __user *win;
|
||||
win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window __user *)(fp + STACK_BIAS);
|
||||
get_user(value, &win->locals[reg - 16]);
|
||||
}
|
||||
return value;
|
||||
@@ -135,19 +138,24 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
|
||||
|
||||
static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fp;
|
||||
|
||||
if (reg < 16)
|
||||
return ®s->u_regs[reg];
|
||||
|
||||
fp = regs->u_regs[UREG_FP];
|
||||
|
||||
if (regs->tstate & TSTATE_PRIV) {
|
||||
struct reg_window *win;
|
||||
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window *)(fp + STACK_BIAS);
|
||||
return &win->locals[reg - 16];
|
||||
} else if (test_thread_flag(TIF_32BIT)) {
|
||||
} else if (!test_thread_64bit_stack(fp)) {
|
||||
struct reg_window32 *win32;
|
||||
win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
|
||||
win32 = (struct reg_window32 *)((unsigned long)((u32)fp));
|
||||
return (unsigned long *)&win32->locals[reg - 16];
|
||||
} else {
|
||||
struct reg_window *win;
|
||||
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window *)(fp + STACK_BIAS);
|
||||
return &win->locals[reg - 16];
|
||||
}
|
||||
}
|
||||
@@ -392,13 +400,15 @@ int handle_popc(u32 insn, struct pt_regs *regs)
|
||||
if (rd)
|
||||
regs->u_regs[rd] = ret;
|
||||
} else {
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
unsigned long fp = regs->u_regs[UREG_FP];
|
||||
|
||||
if (!test_thread_64bit_stack(fp)) {
|
||||
struct reg_window32 __user *win32;
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
|
||||
put_user(ret, &win32->locals[rd - 16]);
|
||||
} else {
|
||||
struct reg_window __user *win;
|
||||
win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window __user *)(fp + STACK_BIAS);
|
||||
put_user(ret, &win->locals[rd - 16]);
|
||||
}
|
||||
}
|
||||
@@ -554,7 +564,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs)
|
||||
reg[0] = 0;
|
||||
if ((insn & 0x780000) == 0x180000)
|
||||
reg[1] = 0;
|
||||
} else if (test_thread_flag(TIF_32BIT)) {
|
||||
} else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) {
|
||||
put_user(0, (int __user *) reg);
|
||||
if ((insn & 0x780000) == 0x180000)
|
||||
put_user(0, ((int __user *) reg) + 1);
|
||||
|
@@ -149,21 +149,24 @@ static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
|
||||
|
||||
static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long value;
|
||||
unsigned long value, fp;
|
||||
|
||||
if (reg < 16)
|
||||
return (!reg ? 0 : regs->u_regs[reg]);
|
||||
|
||||
fp = regs->u_regs[UREG_FP];
|
||||
|
||||
if (regs->tstate & TSTATE_PRIV) {
|
||||
struct reg_window *win;
|
||||
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window *)(fp + STACK_BIAS);
|
||||
value = win->locals[reg - 16];
|
||||
} else if (test_thread_flag(TIF_32BIT)) {
|
||||
} else if (!test_thread_64bit_stack(fp)) {
|
||||
struct reg_window32 __user *win32;
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
|
||||
get_user(value, &win32->locals[reg - 16]);
|
||||
} else {
|
||||
struct reg_window __user *win;
|
||||
win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window __user *)(fp + STACK_BIAS);
|
||||
get_user(value, &win->locals[reg - 16]);
|
||||
}
|
||||
return value;
|
||||
@@ -172,16 +175,18 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
|
||||
static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fp = regs->u_regs[UREG_FP];
|
||||
|
||||
BUG_ON(reg < 16);
|
||||
BUG_ON(regs->tstate & TSTATE_PRIV);
|
||||
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
if (!test_thread_64bit_stack(fp)) {
|
||||
struct reg_window32 __user *win32;
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
|
||||
win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
|
||||
return (unsigned long __user *)&win32->locals[reg - 16];
|
||||
} else {
|
||||
struct reg_window __user *win;
|
||||
win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||
win = (struct reg_window __user *)(fp + STACK_BIAS);
|
||||
return &win->locals[reg - 16];
|
||||
}
|
||||
}
|
||||
@@ -204,7 +209,7 @@ static void store_reg(struct pt_regs *regs, unsigned long val, unsigned long rd)
|
||||
} else {
|
||||
unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs);
|
||||
|
||||
if (test_thread_flag(TIF_32BIT))
|
||||
if (!test_thread_64bit_stack(regs->u_regs[UREG_FP]))
|
||||
__put_user((u32)val, (u32 __user *)rd_user);
|
||||
else
|
||||
__put_user(val, rd_user);
|
||||
|
@@ -43,6 +43,8 @@ spill_fixup_mna:
|
||||
spill_fixup_dax:
|
||||
TRAP_LOAD_THREAD_REG(%g6, %g1)
|
||||
ldx [%g6 + TI_FLAGS], %g1
|
||||
andcc %sp, 0x1, %g0
|
||||
movne %icc, 0, %g1
|
||||
andcc %g1, _TIF_32BIT, %g0
|
||||
ldub [%g6 + TI_WSAVED], %g1
|
||||
sll %g1, 3, %g3
|
||||
|
Reference in New Issue
Block a user