Commit f2a39c2b authored by Pete Zaitcev's avatar Pete Zaitcev Committed by David S. Miller

[SPARC]: Get sun4c functional again in 2.6.0

Move some elements of task_struct into thread_info so that
these elements are locked into the TLB in the trap handlers
and thus will not cause a watchdog reset.
parent 361d16e2
......@@ -38,12 +38,6 @@ int foo(void)
DEFINE(AOFF_thread_fork_kpsr,
offsetof(struct thread_struct, fork_kpsr));
BLANK();
DEFINE(AOFF_thread_w_saved, offsetof(struct thread_struct, w_saved));
DEFINE(AOFF_thread_rwbuf_stkptrs,
offsetof(struct thread_struct, rwbuf_stkptrs));
DEFINE(AOFF_thread_reg_window,
offsetof(struct thread_struct, reg_window));
BLANK();
DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
/* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
......
......@@ -1907,9 +1907,8 @@ kuw_patch1:
wr %o5, 0x0, %psr ! re-enable interrupts
WRITE_PAUSE ! burn baby burn
3:
ld [%g6 + TI_TASK], %o4
retl ! return
st %g0, [%o4 + AOFF_task_thread + AOFF_thread_w_saved] ! no windows saved
st %g0, [%g6 + TI_W_SAVED] ! no windows saved
.align 4
.globl C_LABEL(restore_current)
......
......@@ -12,7 +12,6 @@
#include <asm/page.h>
#include <asm/psr.h>
#include <asm/ptrace.h>
#include <asm/asm_offsets.h>
#include <asm/winmacro.h>
#include <asm/asmmacro.h>
#include <asm/thread_info.h>
......@@ -57,7 +56,7 @@ tsetup_7win_patch6: and %g2, 0x7f, %g2
*
* sethi %hi(trap_setup), %l4
* jmpl %l4 + %lo(trap_setup), %l6
* mov 1, %l4
* nop
*/
/* 2 3 4 window number
......@@ -156,9 +155,8 @@ trap_setup_from_user:
and %t_kstack, %curptr, %curptr
#endif
/* Clear current->thread.w_saved */
ld [%curptr + TI_TASK], %g2
st %g0, [%g2 + AOFF_task_thread + AOFF_thread_w_saved]
/* Clear current_thread_info->w_saved */
st %g0, [%curptr + TI_W_SAVED]
/* See if we are in the trap window. */
andcc %t_twinmask, %t_wim, %g0
......@@ -292,8 +290,7 @@ trap_setup_user_stack_is_bolixed:
/* From user/kernel into invalid window w/bad user
* stack. Save bad user stack, and return to caller.
*/
ld [%curptr + TI_TASK], %glob_tmp
SAVE_BOLIXED_USER_STACK(glob_tmp, g3)
SAVE_BOLIXED_USER_STACK(curptr, g3)
restore %g0, %g0, %g0
jmpl %t_retpc + 0x8, %g0
......
......@@ -356,7 +356,7 @@ void exit_thread(void)
void flush_thread(void)
{
current->thread.w_saved = 0;
current_thread_info()->w_saved = 0;
/* No new signal delivery by default */
current->thread.new_signal = 0;
......@@ -490,9 +490,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
ti->kwim = current->thread.fork_kwim;
/* This is used for sun4c only */
atomic_set(&p->thread.refcount, 1);
if(regs->psr & PSR_PS) {
extern struct pt_regs fake_swapper_regs;
......
......@@ -72,7 +72,7 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
struct task_struct *tsk, long *addr)
{
struct pt_regs *cregs = tsk->thread.kregs;
struct thread_struct *t = &tsk->thread;
struct thread_info *t = tsk->thread_info;
int v;
if(offset >= 1024)
......@@ -93,16 +93,16 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
}
switch(offset) {
case 0:
v = tsk->thread_info->ksp;
v = t->ksp;
break;
case 4:
v = tsk->thread_info->kpc;
v = t->kpc;
break;
case 8:
v = tsk->thread_info->kpsr;
v = t->kpsr;
break;
case 12:
v = tsk->thread_info->uwinmask;
v = t->uwinmask;
break;
case 832:
v = t->w_saved;
......@@ -167,7 +167,7 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
struct task_struct *tsk)
{
struct pt_regs *cregs = tsk->thread.kregs;
struct thread_struct *t = &tsk->thread;
struct thread_info *t = tsk->thread_info;
unsigned long value = regs->u_regs[UREG_I3];
if(offset >= 1024)
......
......@@ -7,7 +7,6 @@
#include <asm/cprefix.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/asm_offsets.h>
#include <asm/psr.h>
#include <asm/asi.h>
#include <asm/smp.h>
......@@ -87,8 +86,7 @@ ret_trap_continue:
wr %t_psr, 0x0, %psr
WRITE_PAUSE
ld [%curptr + TI_TASK], %o5
ld [%o5 + AOFF_task_thread + AOFF_thread_w_saved], %twin_tmp1
ld [%curptr + TI_W_SAVED], %twin_tmp1
orcc %g0, %twin_tmp1, %g0
be ret_trap_nobufwins
nop
......
......@@ -432,6 +432,7 @@ setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *old
int window = 0, err;
unsigned long pc = regs->pc;
unsigned long npc = regs->npc;
struct thread_info *tp = current_thread_info();
void *sig_address;
int sig_code;
......@@ -459,20 +460,20 @@ setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *old
err |= __put_user(regs->psr, &sc->sigc_psr);
err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
err |= __put_user(current->thread.w_saved, &sc->sigc_oswins);
if (current->thread.w_saved)
for (window = 0; window < current->thread.w_saved; window++) {
put_user((char *)current->thread.rwbuf_stkptrs[window],
err |= __put_user(tp->w_saved, &sc->sigc_oswins);
if (tp->w_saved)
for (window = 0; window < tp->w_saved; window++) {
put_user((char *)tp->rwbuf_stkptrs[window],
&sc->sigc_spbuf[window]);
err |= __copy_to_user(&sc->sigc_wbuf[window],
&current->thread.reg_window[window],
&tp->reg_window[window],
sizeof(struct reg_window));
}
else
err |= __copy_to_user(sframep, (char *) regs->u_regs[UREG_FP],
sizeof(struct reg_window));
current->thread.w_saved = 0; /* So process is allowed to execute. */
tp->w_saved = 0; /* So process is allowed to execute. */
err |= __put_user(signr, &sframep->sig_num);
sig_address = NULL;
......@@ -601,7 +602,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill_and_return;
if (current->thread.w_saved != 0)
if (current_thread_info()->w_saved != 0)
goto sigill_and_return;
/* 2. Save the current process state */
......@@ -675,7 +676,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
if (current->thread.w_saved != 0)
if (current_thread_info()->w_saved != 0)
goto sigill;
err = __put_user(regs->pc, &sf->regs.pc);
......@@ -752,6 +753,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_gwindows_t __user *gw;
svr4_ucontext_t __user *uc;
svr4_sigset_t setv;
struct thread_info *tp = current_thread_info();
int window = 0, err;
synchronize_user_stack();
......@@ -808,7 +810,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
err |= __put_user(gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext(): */
err |= __put_user(current->thread.w_saved, &gw->count);
err |= __put_user(tp->w_saved, &gw->count);
/* 3. Save each valid window
* Currently, it makes a copy of the windows from the kernel copy.
......@@ -821,16 +823,16 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* These windows are just used in case synchronize_user_stack failed
* to flush the user windows.
*/
for (window = 0; window < current->thread.w_saved; window++) {
for (window = 0; window < tp->w_saved; window++) {
err |= __put_user((int *) &(gw->win[window]), &gw->winptr[window]);
err |= __copy_to_user(&gw->win[window],
&current->thread.reg_window[window],
&tp->reg_window[window],
sizeof(svr4_rwindow_t));
err |= __put_user(0, gw->winptr[window]);
}
/* 4. We just pay attention to the gw->count field on setcontext */
current->thread.w_saved = 0; /* So process is allowed to execute. */
tp->w_saved = 0; /* So process is allowed to execute. */
/* Setup the signal information. Solaris expects a bunch of
* information to be passed to the signal handler, we don't provide
......@@ -878,7 +880,7 @@ asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
synchronize_user_stack();
if (current->thread.w_saved)
if (current_thread_info()->w_saved)
goto sigsegv_and_return;
err = clear_user(uc, sizeof(*uc));
......@@ -928,7 +930,6 @@ asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs)
{
struct thread_struct *tp = &current->thread;
svr4_gregset_t __user *gr;
unsigned long pc, npc, psr;
sigset_t set;
......@@ -940,8 +941,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs)
* svr4_setup_frame when sync_user_windows is done?
*/
flush_user_windows();
if (tp->w_saved)
if (current_thread_info()->w_saved)
goto sigsegv_and_return;
if (((uint) c) & 3)
......
......@@ -497,7 +497,10 @@ void trap_init(void)
TI_KSP != offsetof(struct thread_info, ksp) ||
TI_KPC != offsetof(struct thread_info, kpc) ||
TI_KPSR != offsetof(struct thread_info, kpsr) ||
TI_KWIM != offsetof(struct thread_info, kwim))
TI_KWIM != offsetof(struct thread_info, kwim) ||
TI_REG_WINDOW != offsetof(struct thread_info, reg_window) ||
TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) ||
TI_W_SAVED != offsetof(struct thread_info, w_saved))
thread_info_offsets_are_bolixed_pete();
/* Attach to the address space of init_task. */
......
......@@ -36,7 +36,7 @@ void flush_user_windows(void)
: "g4", "cc");
}
static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp)
static inline void shift_window_buffer(int first_win, int last_win, struct thread_info *tp)
{
int i;
......@@ -57,11 +57,10 @@ static inline void shift_window_buffer(int first_win, int last_win, struct threa
*/
void synchronize_user_stack(void)
{
struct thread_struct *tp;
struct thread_info *tp = current_thread_info();
int window;
flush_user_windows();
tp = &current->thread;
if(!tp->w_saved)
return;
......@@ -110,12 +109,11 @@ static inline void copy_aligned_window(void *dest, const void *src)
void try_to_clear_window_buffer(struct pt_regs *regs, int who)
{
struct thread_struct *tp;
struct thread_info *tp = current_thread_info();
int window;
lock_kernel();
flush_user_windows();
tp = &current->thread;
for(window = 0; window < tp->w_saved; window++) {
unsigned long sp = tp->rwbuf_stkptrs[window];
......
......@@ -8,7 +8,6 @@
#include <asm/contregs.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/asm_offsets.h>
#include <asm/psr.h>
#include <asm/smp.h>
#include <asm/asi.h>
......@@ -211,20 +210,18 @@ spwin_user_stack_is_bolixed:
bne spwin_bad_ustack_from_kernel
nop
ld [%curptr + TI_TASK], %glob_tmp
/* Oh well, throw this one window into the per-task window
* buffer, the first one.
*/
st %sp, [%glob_tmp + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
STORE_WINDOW(glob_tmp + AOFF_task_thread + AOFF_thread_reg_window)
st %sp, [%curptr + TI_RWIN_SPTRS]
STORE_WINDOW(curptr + TI_REG_WINDOW)
restore %g0, %g0, %g0
/* LOCATION: Trap Window */
/* Back in the trap window, update winbuffer save count. */
mov 1, %twin_tmp
st %twin_tmp, [%glob_tmp + AOFF_task_thread + AOFF_thread_w_saved]
st %twin_tmp, [%curptr + TI_W_SAVED]
/* Compute new user window mask. What we are basically
* doing is taking two windows, the invalid one at trap
......@@ -275,8 +272,7 @@ spwin_bad_ustack_from_kernel:
* a per-process window buffer until we can properly handle
* this later on.
*/
ld [%curptr + TI_TASK], %glob_tmp /* Using curptr one last time */
SAVE_BOLIXED_USER_STACK(glob_tmp, g6) /* ...now using g6 as scratch */
SAVE_BOLIXED_USER_STACK(curptr, glob_tmp)
restore %g0, %g0, %g0
/* LOCATION: Trap window */
......
......@@ -8,7 +8,6 @@
#include <asm/contregs.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/asm_offsets.h>
#include <asm/psr.h>
#include <asm/smp.h>
#include <asm/asi.h>
......@@ -187,8 +186,7 @@ fwin_user_stack_is_bolixed:
mov 0x1, %g5
sll %g5, %g3, %g5
st %g5, [%curptr + TI_UWINMASK] ! one live user window still
ld [%curptr + TI_TASK], %g5
st %g0, [%g5 + AOFF_task_thread + AOFF_thread_w_saved] ! no windows in the buffer
st %g0, [%curptr + TI_W_SAVED] ! no windows in the buffer
wr %t_psr, PSR_ET, %psr ! enable traps
nop
......
......@@ -550,7 +550,7 @@ void window_overflow_fault(void)
{
unsigned long sp;
sp = current->thread.rwbuf_stkptrs[0];
sp = current_thread_info()->rwbuf_stkptrs[0];
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 1);
force_user_fault(sp, 1);
......
......@@ -209,7 +209,8 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
if (max_low_pfn > (SRMMU_MAXMEM >> PAGE_SHIFT)) {
highstart_pfn = (SRMMU_MAXMEM >> PAGE_SHIFT);
max_low_pfn = calc_max_low_pfn();
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", calc_highpages());
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
calc_highpages() >> (20 - PAGE_SHIFT));
}
#ifdef CONFIG_BLK_DEV_INITRD
......
......@@ -1067,23 +1067,21 @@ static void sun4c_free_thread_info(struct thread_info *ti)
unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tiaddr));
int entry = BUCKET_NUM(tiaddr);
if (atomic_dec_and_test(&ti->task->thread.refcount)) {
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page(tiaddr);
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page(tiaddr);
#ifndef CONFIG_SUN4
sun4c_flush_page(tiaddr + PAGE_SIZE);
sun4c_flush_page(tiaddr + PAGE_SIZE);
#endif
sun4c_put_pte(tiaddr, 0);
sun4c_put_pte(tiaddr, 0);
#ifndef CONFIG_SUN4
sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
#endif
sun4c_bucket[entry] = BUCKET_EMPTY;
if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
sun4c_bucket[entry] = BUCKET_EMPTY;
if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
free_pages(pages, THREAD_INFO_ORDER);
garbage_collect(entry);
}
free_pages(pages, THREAD_INFO_ORDER);
garbage_collect(entry);
}
static void __init sun4c_init_buckets(void)
......
......@@ -56,19 +56,12 @@ typedef struct {
/* The Sparc processor specific thread struct. */
struct thread_struct {
struct pt_regs *kregs;
unsigned int _pad1;
/* Special child fork kpsr/kwim values. */
unsigned long fork_kpsr __attribute__ ((aligned (8)));
unsigned long fork_kwim;
/* A place to store user windows and stack pointers
* when the stack needs inspection.
*/
#define NSWINS 8
struct reg_window reg_window[NSWINS] __attribute__ ((aligned (8)));
unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
unsigned long w_saved;
/* Floating point regs */
unsigned long float_regs[32] __attribute__ ((aligned (8)));
unsigned long fsr;
......@@ -78,23 +71,16 @@ struct thread_struct {
mm_segment_t current_ds;
struct exec core_exec; /* just what it says. */
int new_signal;
atomic_t refcount; /* used for sun4c only */
};
#define SPARC_FLAG_KTHREAD 0x1 /* task is a kernel thread */
#define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */
#define INIT_THREAD { \
/* kregs, */ \
0, \
/* kregs, _pad1, */ \
0, 0, \
/* fork_kpsr, fork_kwim */ \
0, 0, \
/* reg_window */ \
{ { { 0, }, { 0, } }, }, \
/* rwbuf_stkptrs */ \
{ 0, 0, 0, 0, 0, 0, 0, 0, }, \
/* w_saved */ \
0, \
/* FPU regs */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
/* FPU status, FPU qdepth, FPU queue */ \
......
......@@ -16,16 +16,14 @@
#ifndef __ASSEMBLY__
#include <asm/btfixup.h>
#include <asm/ptrace.h>
/*
* Low level task data.
*
* If you change this, change the TI_* offsets below to match. XXX check_asm.
*
* The uwinmask is a first class citizen among w_saved and friends.
* XXX Is this a good idea? wof.S/wuf.S have to use w_saved anyway,
* so they waste a register on current, and an ld on fetching it.
* If you change this, change the TI_* offsets below to match.
*/
#define NSWINS 8
struct thread_info {
unsigned long uwinmask;
struct task_struct *task; /* main task structure */
......@@ -43,6 +41,13 @@ struct thread_info {
unsigned long kpsr;
unsigned long kwim;
/* A place to store user windows and stack pointers
* when the stack needs inspection.
*/
struct reg_window reg_window[NSWINS]; /* align for ldd! */
unsigned long rwbuf_stkptrs[NSWINS];
unsigned long w_saved;
struct restart_block restart_block;
};
......@@ -100,6 +105,7 @@ BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
/*
* Offsets in thread_info structure, used in assembly code
* The "#define REGWIN_SZ 0x40" was abolished, so no multiplications.
*/
#define TI_UWINMASK 0x00 /* uwinmask */
#define TI_TASK 0x04
......@@ -113,7 +119,10 @@ BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
#define TI_KPC 0x24 /* kpc (ldd'ed with kpc) */
#define TI_KPSR 0x28 /* kpsr */
#define TI_KWIM 0x2c /* kwim (ldd'ed with kpsr) */
#define TI_RESTART_BLOCK 0x30
#define TI_REG_WINDOW 0x30
#define TI_RWIN_SPTRS 0x230
#define TI_W_SAVED 0x250
/* #define TI_RESTART_BLOCK 0x25n */ /* Nobody cares */
#define PREEMPT_ACTIVE 0x4000000
......
......@@ -9,7 +9,6 @@
#include <linux/config.h>
#include <asm/ptrace.h>
#include <asm/psr.h>
/* Store the register window onto the 8-byte aligned area starting
* at %reg. It might be %sp, it might not, we don't care.
......@@ -91,18 +90,18 @@
STORE_PT_INS(base_reg)
#define SAVE_BOLIXED_USER_STACK(cur_reg, scratch) \
ld [%cur_reg + AOFF_task_thread + AOFF_thread_w_saved], %scratch; \
ld [%cur_reg + TI_W_SAVED], %scratch; \
sll %scratch, 2, %scratch; \
add %scratch, %cur_reg, %scratch; \
st %sp, [%scratch + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]; \
st %sp, [%scratch + TI_RWIN_SPTRS]; \
sub %scratch, %cur_reg, %scratch; \
sll %scratch, 4, %scratch; \
add %scratch, %cur_reg, %scratch; \
STORE_WINDOW(scratch + AOFF_task_thread + AOFF_thread_reg_window); \
STORE_WINDOW(scratch + TI_REG_WINDOW); \
sub %scratch, %cur_reg, %scratch; \
srl %scratch, 6, %scratch; \
add %scratch, 1, %scratch; \
st %scratch, [%cur_reg + AOFF_task_thread + AOFF_thread_w_saved];
st %scratch, [%cur_reg + TI_W_SAVED];
#ifdef CONFIG_SMP
#define LOAD_CURRENT4M(dest_reg, idreg) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment