Skip to content

Commit

Permalink
Merge branch 'arch-sparc' into no-rebases
Browse files Browse the repository at this point in the history
  • Loading branch information
Al Viro committed Nov 17, 2012
2 parents 48944cc + 85910c2 commit d042f31
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 61 deletions.
5 changes: 3 additions & 2 deletions arch/sparc/include/asm/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,10 @@ static inline void __user *arch_compat_alloc_user_space(long len)
struct pt_regs *regs = current_thread_info()->kregs;
unsigned long usp = regs->u_regs[UREG_I6];

if (!(test_thread_flag(TIF_32BIT)))
if (test_thread_64bit_stack(usp))
usp += STACK_BIAS;
else

if (test_thread_flag(TIF_32BIT))
usp &= 0xffffffffUL;

usp -= len;
Expand Down
5 changes: 5 additions & 0 deletions arch/sparc/include/asm/thread_info_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ static inline bool test_and_clear_restore_sigmask(void)

#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)

#define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0)
#define test_thread_64bit_stack(__SP) \
((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \
false : true)

#endif /* !__ASSEMBLY__ */

#endif /* __KERNEL__ */
Expand Down
24 changes: 16 additions & 8 deletions arch/sparc/include/asm/ttable.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,9 @@ etrap_spill_fixup_64bit: \

/* Normal 32bit spill */
#define SPILL_2_GENERIC(ASI) \
srl %sp, 0, %sp; \
and %sp, 1, %g3; \
brnz,pn %g3, (. - (128 + 4)); \
srl %sp, 0, %sp; \
stwa %l0, [%sp + %g0] ASI; \
mov 0x04, %g3; \
stwa %l1, [%sp + %g3] ASI; \
Expand All @@ -398,14 +400,16 @@ etrap_spill_fixup_64bit: \
stwa %i6, [%g1 + %g0] ASI; \
stwa %i7, [%g1 + %g3] ASI; \
saved; \
retry; nop; nop; \
retry; \
b,a,pt %xcc, spill_fixup_dax; \
b,a,pt %xcc, spill_fixup_mna; \
b,a,pt %xcc, spill_fixup;

#define SPILL_2_GENERIC_ETRAP \
etrap_user_spill_32bit: \
srl %sp, 0, %sp; \
and %sp, 1, %g3; \
brnz,pn %g3, etrap_user_spill_64bit; \
srl %sp, 0, %sp; \
stwa %l0, [%sp + 0x00] %asi; \
stwa %l1, [%sp + 0x04] %asi; \
stwa %l2, [%sp + 0x08] %asi; \
Expand All @@ -427,7 +431,7 @@ etrap_user_spill_32bit: \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop; nop; \
nop; nop; nop; nop; \
nop; nop; \
ba,a,pt %xcc, etrap_spill_fixup_32bit; \
ba,a,pt %xcc, etrap_spill_fixup_32bit; \
ba,a,pt %xcc, etrap_spill_fixup_32bit;
Expand Down Expand Up @@ -592,7 +596,9 @@ user_rtt_fill_64bit: \

/* Normal 32bit fill */
#define FILL_2_GENERIC(ASI) \
srl %sp, 0, %sp; \
and %sp, 1, %g3; \
brnz,pn %g3, (. - (128 + 4)); \
srl %sp, 0, %sp; \
lduwa [%sp + %g0] ASI, %l0; \
mov 0x04, %g2; \
mov 0x08, %g3; \
Expand All @@ -616,14 +622,16 @@ user_rtt_fill_64bit: \
lduwa [%g1 + %g3] ASI, %i6; \
lduwa [%g1 + %g5] ASI, %i7; \
restored; \
retry; nop; nop; nop; nop; \
retry; nop; nop; \
b,a,pt %xcc, fill_fixup_dax; \
b,a,pt %xcc, fill_fixup_mna; \
b,a,pt %xcc, fill_fixup;

#define FILL_2_GENERIC_RTRAP \
user_rtt_fill_32bit: \
srl %sp, 0, %sp; \
and %sp, 1, %g3; \
brnz,pn %g3, user_rtt_fill_64bit; \
srl %sp, 0, %sp; \
lduwa [%sp + 0x00] %asi, %l0; \
lduwa [%sp + 0x04] %asi, %l1; \
lduwa [%sp + 0x08] %asi, %l2; \
Expand All @@ -643,7 +651,7 @@ user_rtt_fill_32bit: \
ba,pt %xcc, user_rtt_pre_restore; \
restored; \
nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; \
nop; nop; nop; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup;
Expand Down
6 changes: 5 additions & 1 deletion arch/sparc/include/uapi/asm/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,12 @@
#define __NR_setns 337
#define __NR_process_vm_readv 338
#define __NR_process_vm_writev 339
#define __NR_kern_features 340

#define NR_syscalls 340
#define NR_syscalls 341

/* Bitmask values returned from kern_features system call. */
#define KERN_FEATURE_MIXED_MODE_STACK 0x00000001

#ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
Expand Down
22 changes: 16 additions & 6 deletions arch/sparc/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1762,15 +1762,25 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,

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);
}
Expand Down
42 changes: 23 additions & 19 deletions arch/sparc/kernel/process_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,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]));

Expand All @@ -472,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;
Expand Down Expand Up @@ -507,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);
Expand All @@ -544,22 +547,23 @@ 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();

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);
Expand Down
4 changes: 2 additions & 2 deletions arch/sparc/kernel/ptrace_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions arch/sparc/kernel/sys_sparc_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions arch/sparc/kernel/systbls_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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
36 changes: 23 additions & 13 deletions arch/sparc/kernel/unaligned_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,41 +113,49 @@ 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;
}

static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
{
unsigned long fp;

if (reg < 16)
return &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);
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];
}
}
Expand Down Expand Up @@ -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]);
}
}
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit d042f31

Please sign in to comment.