Commit 87d2fed7 authored by Al Viro's avatar Al Viro

Merge branch 'arch-sparc' into no-rebases

parents fefec52b f7200d4c
...@@ -40,6 +40,8 @@ config SPARC ...@@ -40,6 +40,8 @@ config SPARC
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
config SPARC32 config SPARC32
def_bool !64BIT def_bool !64BIT
......
...@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, ...@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
#define release_thread(tsk) do { } while(0) #define release_thread(tsk) do { } while(0)
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long get_wchan(struct task_struct *); extern unsigned long get_wchan(struct task_struct *);
......
...@@ -94,6 +94,7 @@ struct thread_struct { ...@@ -94,6 +94,7 @@ struct thread_struct {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/types.h> #include <linux/types.h>
#include <asm/fpumacro.h>
/* Return saved PC of a blocked thread. */ /* Return saved PC of a blocked thread. */
struct task_struct; struct task_struct;
...@@ -143,6 +144,10 @@ do { \ ...@@ -143,6 +144,10 @@ do { \
: \ : \
: "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \ : "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \
"i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
fprs_write(0); \
current_thread_info()->xfsr[0] = 0; \
current_thread_info()->fpsaved[0] = 0; \
regs->tstate &= ~TSTATE_PEF; \
} while (0) } while (0)
#define start_thread32(regs, pc, sp) \ #define start_thread32(regs, pc, sp) \
...@@ -183,13 +188,15 @@ do { \ ...@@ -183,13 +188,15 @@ do { \
: \ : \
: "r" (regs), "r" (sp - sizeof(struct reg_window32)), \ : "r" (regs), "r" (sp - sizeof(struct reg_window32)), \
"i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
fprs_write(0); \
current_thread_info()->xfsr[0] = 0; \
current_thread_info()->fpsaved[0] = 0; \
regs->tstate &= ~TSTATE_PEF; \
} while (0) } while (0)
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
#define release_thread(tsk) do { } while (0) #define release_thread(tsk) do { } while (0)
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long get_wchan(struct task_struct *task); extern unsigned long get_wchan(struct task_struct *task);
#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
......
...@@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) ...@@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
#define arch_ptrace_stop(exit_code, info) \ #define arch_ptrace_stop(exit_code, info) \
synchronize_user_stack() synchronize_user_stack()
#define current_pt_regs() \
((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
struct global_reg_snapshot { struct global_reg_snapshot {
unsigned long tstate; unsigned long tstate;
unsigned long tpc; unsigned long tpc;
...@@ -44,9 +47,7 @@ struct global_reg_snapshot { ...@@ -44,9 +47,7 @@ struct global_reg_snapshot {
}; };
extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
#define force_successful_syscall_return() \ #define force_successful_syscall_return() set_thread_noerror(1)
do { current_thread_info()->syscall_noerror = 1; \
} while (0)
#define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
#define instruction_pointer(regs) ((regs)->tpc) #define instruction_pointer(regs) ((regs)->tpc)
#define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) #define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
...@@ -89,6 +90,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) ...@@ -89,6 +90,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
#define arch_ptrace_stop(exit_code, info) \ #define arch_ptrace_stop(exit_code, info) \
synchronize_user_stack() synchronize_user_stack()
#define current_pt_regs() \
((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
#define user_mode(regs) (!((regs)->psr & PSR_PS)) #define user_mode(regs) (!((regs)->psr & PSR_PS))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
......
...@@ -23,7 +23,7 @@ do { flush_tlb_pending(); \ ...@@ -23,7 +23,7 @@ do { flush_tlb_pending(); \
/* If you are tempted to conditionalize the following */ \ /* If you are tempted to conditionalize the following */ \
/* so that ASI is only written if it changes, think again. */ \ /* so that ASI is only written if it changes, think again. */ \
__asm__ __volatile__("wr %%g0, %0, %%asi" \ __asm__ __volatile__("wr %%g0, %0, %%asi" \
: : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ : : "r" (task_thread_info(next)->current_ds));\
trap_block[current_thread_info()->cpu].thread = \ trap_block[current_thread_info()->cpu].thread = \
task_thread_info(next); \ task_thread_info(next); \
__asm__ __volatile__( \ __asm__ __volatile__( \
......
...@@ -8,6 +8,4 @@ extern asmlinkage long sparc_do_fork(unsigned long clone_flags, ...@@ -8,6 +8,4 @@ extern asmlinkage long sparc_do_fork(unsigned long clone_flags,
struct pt_regs *regs, struct pt_regs *regs,
unsigned long stack_size); unsigned long stack_size);
extern asmlinkage int sparc_execve(struct pt_regs *regs);
#endif /* _SPARC64_SYSCALLS_H */ #endif /* _SPARC64_SYSCALLS_H */
...@@ -14,12 +14,12 @@ ...@@ -14,12 +14,12 @@
#define TI_FLAG_FAULT_CODE_SHIFT 56 #define TI_FLAG_FAULT_CODE_SHIFT 56
#define TI_FLAG_BYTE_WSTATE 1 #define TI_FLAG_BYTE_WSTATE 1
#define TI_FLAG_WSTATE_SHIFT 48 #define TI_FLAG_WSTATE_SHIFT 48
#define TI_FLAG_BYTE_CWP 2 #define TI_FLAG_BYTE_NOERROR 2
#define TI_FLAG_CWP_SHIFT 40 #define TI_FLAG_BYTE_NOERROR_SHIFT 40
#define TI_FLAG_BYTE_CURRENT_DS 3 #define TI_FLAG_BYTE_FPDEPTH 3
#define TI_FLAG_CURRENT_DS_SHIFT 32 #define TI_FLAG_FPDEPTH_SHIFT 32
#define TI_FLAG_BYTE_FPDEPTH 4 #define TI_FLAG_BYTE_CWP 4
#define TI_FLAG_FPDEPTH_SHIFT 24 #define TI_FLAG_CWP_SHIFT 24
#define TI_FLAG_BYTE_WSAVED 5 #define TI_FLAG_BYTE_WSAVED 5
#define TI_FLAG_WSAVED_SHIFT 16 #define TI_FLAG_WSAVED_SHIFT 16
...@@ -47,7 +47,7 @@ struct thread_info { ...@@ -47,7 +47,7 @@ struct thread_info {
struct exec_domain *exec_domain; struct exec_domain *exec_domain;
int preempt_count; /* 0 => preemptable, <0 => BUG */ int preempt_count; /* 0 => preemptable, <0 => BUG */
__u8 new_child; __u8 new_child;
__u8 syscall_noerror; __u8 current_ds;
__u16 cpu; __u16 cpu;
unsigned long *utraps; unsigned long *utraps;
...@@ -74,9 +74,9 @@ struct thread_info { ...@@ -74,9 +74,9 @@ struct thread_info {
#define TI_FAULT_CODE (TI_FLAGS + TI_FLAG_BYTE_FAULT_CODE) #define TI_FAULT_CODE (TI_FLAGS + TI_FLAG_BYTE_FAULT_CODE)
#define TI_WSTATE (TI_FLAGS + TI_FLAG_BYTE_WSTATE) #define TI_WSTATE (TI_FLAGS + TI_FLAG_BYTE_WSTATE)
#define TI_CWP (TI_FLAGS + TI_FLAG_BYTE_CWP) #define TI_CWP (TI_FLAGS + TI_FLAG_BYTE_CWP)
#define TI_CURRENT_DS (TI_FLAGS + TI_FLAG_BYTE_CURRENT_DS)
#define TI_FPDEPTH (TI_FLAGS + TI_FLAG_BYTE_FPDEPTH) #define TI_FPDEPTH (TI_FLAGS + TI_FLAG_BYTE_FPDEPTH)
#define TI_WSAVED (TI_FLAGS + TI_FLAG_BYTE_WSAVED) #define TI_WSAVED (TI_FLAGS + TI_FLAG_BYTE_WSAVED)
#define TI_SYS_NOERROR (TI_FLAGS + TI_FLAG_BYTE_NOERROR)
#define TI_FPSAVED 0x00000010 #define TI_FPSAVED 0x00000010
#define TI_KSP 0x00000018 #define TI_KSP 0x00000018
#define TI_FAULT_ADDR 0x00000020 #define TI_FAULT_ADDR 0x00000020
...@@ -84,7 +84,7 @@ struct thread_info { ...@@ -84,7 +84,7 @@ struct thread_info {
#define TI_EXEC_DOMAIN 0x00000030 #define TI_EXEC_DOMAIN 0x00000030
#define TI_PRE_COUNT 0x00000038 #define TI_PRE_COUNT 0x00000038
#define TI_NEW_CHILD 0x0000003c #define TI_NEW_CHILD 0x0000003c
#define TI_SYS_NOERROR 0x0000003d #define TI_CURRENT_DS 0x0000003d
#define TI_CPU 0x0000003e #define TI_CPU 0x0000003e
#define TI_UTRAPS 0x00000040 #define TI_UTRAPS 0x00000040
#define TI_REG_WINDOW 0x00000048 #define TI_REG_WINDOW 0x00000048
...@@ -121,7 +121,7 @@ struct thread_info { ...@@ -121,7 +121,7 @@ struct thread_info {
#define INIT_THREAD_INFO(tsk) \ #define INIT_THREAD_INFO(tsk) \
{ \ { \
.task = &tsk, \ .task = &tsk, \
.flags = ((unsigned long)ASI_P) << TI_FLAG_CURRENT_DS_SHIFT, \ .current_ds = ASI_P, \
.exec_domain = &default_exec_domain, \ .exec_domain = &default_exec_domain, \
.preempt_count = INIT_PREEMPT_COUNT, \ .preempt_count = INIT_PREEMPT_COUNT, \
.restart_block = { \ .restart_block = { \
...@@ -153,13 +153,12 @@ register struct thread_info *current_thread_info_reg asm("g6"); ...@@ -153,13 +153,12 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define set_thread_wstate(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSTATE] = (val)) #define set_thread_wstate(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSTATE] = (val))
#define get_thread_cwp() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP]) #define get_thread_cwp() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP])
#define set_thread_cwp(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP] = (val)) #define set_thread_cwp(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP] = (val))
#define get_thread_current_ds() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS]) #define get_thread_noerror() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR])
#define set_thread_current_ds(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS] = (val)) #define set_thread_noerror(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR] = (val))
#define get_thread_fpdepth() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH]) #define get_thread_fpdepth() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH])
#define set_thread_fpdepth(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val)) #define set_thread_fpdepth(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val))
#define get_thread_wsaved() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED]) #define get_thread_wsaved() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED])
#define set_thread_wsaved(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val)) #define set_thread_wsaved(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val))
#endif /* !(__ASSEMBLY__) */ #endif /* !(__ASSEMBLY__) */
/* /*
......
...@@ -38,14 +38,14 @@ ...@@ -38,14 +38,14 @@
#define VERIFY_READ 0 #define VERIFY_READ 0
#define VERIFY_WRITE 1 #define VERIFY_WRITE 1
#define get_fs() ((mm_segment_t) { get_thread_current_ds() }) #define get_fs() ((mm_segment_t){(current_thread_info()->current_ds)})
#define get_ds() (KERNEL_DS) #define get_ds() (KERNEL_DS)
#define segment_eq(a,b) ((a).seg == (b).seg) #define segment_eq(a,b) ((a).seg == (b).seg)
#define set_fs(val) \ #define set_fs(val) \
do { \ do { \
set_thread_current_ds((val).seg); \ current_thread_info()->current_ds =(val).seg; \
__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \ __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \
} while(0) } while(0)
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif #endif
#define __ARCH_WANT_SYS_EXECVE
/* /*
* "Conditional" syscalls * "Conditional" syscalls
......
...@@ -806,23 +806,10 @@ sys_nis_syscall: ...@@ -806,23 +806,10 @@ sys_nis_syscall:
call c_sys_nis_syscall call c_sys_nis_syscall
mov %l5, %o7 mov %l5, %o7
.align 4
.globl sys_execve
sys_execve:
mov %o7, %l5
add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg
call sparc_execve
mov %l5, %o7
.globl sunos_execv
sunos_execv: sunos_execv:
st %g0, [%sp + STACKFRAME_SZ + PT_I2] .globl sunos_execv
b sys_execve
call sparc_execve clr %i2
add %sp, STACKFRAME_SZ, %o0
b ret_sys_call
ld [%sp + STACKFRAME_SZ + PT_I0], %o0
.align 4 .align 4
.globl sys_sparc_pipe .globl sys_sparc_pipe
...@@ -959,17 +946,9 @@ flush_patch_four: ...@@ -959,17 +946,9 @@ flush_patch_four:
.align 4 .align 4
linux_sparc_ni_syscall: linux_sparc_ni_syscall:
sethi %hi(sys_ni_syscall), %l7 sethi %hi(sys_ni_syscall), %l7
b syscall_is_too_hard b do_syscall
or %l7, %lo(sys_ni_syscall), %l7 or %l7, %lo(sys_ni_syscall), %l7
linux_fast_syscall:
andn %l7, 3, %l7
mov %i0, %o0
mov %i1, %o1
mov %i2, %o2
jmpl %l7 + %g0, %g0
mov %i3, %o3
linux_syscall_trace: linux_syscall_trace:
add %sp, STACKFRAME_SZ, %o0 add %sp, STACKFRAME_SZ, %o0
call syscall_trace call syscall_trace
...@@ -991,6 +970,23 @@ ret_from_fork: ...@@ -991,6 +970,23 @@ ret_from_fork:
b ret_sys_call b ret_sys_call
ld [%sp + STACKFRAME_SZ + PT_I0], %o0 ld [%sp + STACKFRAME_SZ + PT_I0], %o0
.globl ret_from_kernel_thread
ret_from_kernel_thread:
call schedule_tail
ld [%g3 + TI_TASK], %o0
ld [%sp + STACKFRAME_SZ + PT_G1], %l0
call %l0
ld [%sp + STACKFRAME_SZ + PT_G2], %o0
rd %psr, %l1
ld [%sp + STACKFRAME_SZ + PT_PSR], %l0
andn %l0, PSR_CWP, %l0
nop
and %l1, PSR_CWP, %l1
or %l0, %l1, %l0
st %l0, [%sp + STACKFRAME_SZ + PT_PSR]
b ret_sys_call
mov 0, %o0
/* Linux native system calls enter here... */ /* Linux native system calls enter here... */
.align 4 .align 4
.globl linux_sparc_syscall .globl linux_sparc_syscall
...@@ -1002,11 +998,8 @@ linux_sparc_syscall: ...@@ -1002,11 +998,8 @@ linux_sparc_syscall:
bgeu linux_sparc_ni_syscall bgeu linux_sparc_ni_syscall
sll %g1, 2, %l4 sll %g1, 2, %l4
ld [%l7 + %l4], %l7 ld [%l7 + %l4], %l7
andcc %l7, 1, %g0
bne linux_fast_syscall
/* Just do first insn from SAVE_ALL in the delay slot */
syscall_is_too_hard: do_syscall:
SAVE_ALL_HEAD SAVE_ALL_HEAD
rd %wim, %l3 rd %wim, %l3
......
...@@ -92,8 +92,10 @@ etrap_save: save %g2, -STACK_BIAS, %sp ...@@ -92,8 +92,10 @@ etrap_save: save %g2, -STACK_BIAS, %sp
rdpr %wstate, %g2 rdpr %wstate, %g2
wrpr %g0, 0, %canrestore wrpr %g0, 0, %canrestore
sll %g2, 3, %g2 sll %g2, 3, %g2
/* Set TI_SYS_FPDEPTH to 1 and clear TI_SYS_NOERROR. */
mov 1, %l5 mov 1, %l5
stb %l5, [%l6 + TI_FPDEPTH] sth %l5, [%l6 + TI_SYS_NOERROR]
wrpr %g3, 0, %otherwin wrpr %g3, 0, %otherwin
wrpr %g2, 0, %wstate wrpr %g2, 0, %wstate
...@@ -152,7 +154,9 @@ etrap_save: save %g2, -STACK_BIAS, %sp ...@@ -152,7 +154,9 @@ etrap_save: save %g2, -STACK_BIAS, %sp
add %l6, TI_FPSAVED + 1, %l4 add %l6, TI_FPSAVED + 1, %l4
srl %l5, 1, %l3 srl %l5, 1, %l3
add %l5, 2, %l5 add %l5, 2, %l5
stb %l5, [%l6 + TI_FPDEPTH]
/* Set TI_SYS_FPDEPTH to %l5 and clear TI_SYS_NOERROR. */
sth %l5, [%l6 + TI_SYS_NOERROR]
ba,pt %xcc, 2b ba,pt %xcc, 2b
stb %g0, [%l4 + %l3] stb %g0, [%l4 + %l3]
nop nop
......
...@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, ...@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
* XXX See comment above sys_vfork in sparc64. todo. * XXX See comment above sys_vfork in sparc64. todo.
*/ */
extern void ret_from_fork(void); extern void ret_from_fork(void);
extern void ret_from_kernel_thread(void);
int copy_thread(unsigned long clone_flags, unsigned long sp, int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long unused, unsigned long arg,
struct task_struct *p, struct pt_regs *regs) struct task_struct *p, struct pt_regs *regs)
{ {
struct thread_info *ti = task_thread_info(p); struct thread_info *ti = task_thread_info(p);
...@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
} }
/* /*
* p->thread_info new_stack childregs * p->thread_info new_stack childregs stack bottom
* ! ! ! {if(PSR_PS) } * ! ! ! !
* V V (stk.fr.) V (pt_regs) { (stk.fr.) } * V V (stk.fr.) V (pt_regs) V
* +----- - - - - - ------+===========+============={+==========}+ * +----- - - - - - ------+===========+=============+
*/ */
new_stack = task_stack_page(p) + THREAD_SIZE; new_stack = task_stack_page(p) + THREAD_SIZE;
if (regs->psr & PSR_PS)
new_stack -= STACKFRAME_SZ;
new_stack -= STACKFRAME_SZ + TRACEREG_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
/* /*
...@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
* Thus, kpsr|=PSR_PIL. * Thus, kpsr|=PSR_PIL.
*/ */
ti->ksp = (unsigned long) new_stack; ti->ksp = (unsigned long) new_stack;
p->thread.kregs = childregs;
if (unlikely(p->flags & PF_KTHREAD)) {
extern int nwindows;
unsigned long psr;
memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
p->thread.flags |= SPARC_FLAG_KTHREAD;
p->thread.current_ds = KERNEL_DS;
ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
childregs->u_regs[UREG_G1] = sp; /* function */
childregs->u_regs[UREG_G2] = arg;
psr = childregs->psr = get_psr();
ti->kpsr = psr | PSR_PIL;
ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows);
return 0;
}
memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
childregs->u_regs[UREG_FP] = sp;
p->thread.flags &= ~SPARC_FLAG_KTHREAD;
p->thread.current_ds = USER_DS;
ti->kpc = (((unsigned long) ret_from_fork) - 0x8); ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
ti->kwim = current->thread.fork_kwim; ti->kwim = current->thread.fork_kwim;
if(regs->psr & PSR_PS) { if (sp != regs->u_regs[UREG_FP]) {
extern struct pt_regs fake_swapper_regs; struct sparc_stackf __user *childstack;
struct sparc_stackf __user *parentstack;
p->thread.kregs = &fake_swapper_regs; /*
new_stack += STACKFRAME_SZ + TRACEREG_SZ; * This is a clone() call with supplied user stack.
childregs->u_regs[UREG_FP] = (unsigned long) new_stack; * Set some valid stack frames to give to the child.
p->thread.flags |= SPARC_FLAG_KTHREAD; */
p->thread.current_ds = KERNEL_DS; childstack = (struct sparc_stackf __user *)
memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); (sp & ~0xfUL);
childregs->u_regs[UREG_G6] = (unsigned long) ti; parentstack = (struct sparc_stackf __user *)
} else { regs->u_regs[UREG_FP];
p->thread.kregs = childregs;
childregs->u_regs[UREG_FP] = sp;
p->thread.flags &= ~SPARC_FLAG_KTHREAD;
p->thread.current_ds = USER_DS;
if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf __user *childstack;
struct sparc_stackf __user *parentstack;
/*
* This is a clone() call with supplied user stack.
* Set some valid stack frames to give to the child.
*/
childstack = (struct sparc_stackf __user *)
(sp & ~0xfUL);
parentstack = (struct sparc_stackf __user *)
regs->u_regs[UREG_FP];
#if 0 #if 0
printk("clone: parent stack:\n"); printk("clone: parent stack:\n");
show_stackframe(parentstack); show_stackframe(parentstack);
#endif #endif
childstack = clone_stackframe(childstack, parentstack); childstack = clone_stackframe(childstack, parentstack);
if (!childstack) if (!childstack)
return -EFAULT; return -EFAULT;
#if 0 #if 0
printk("clone: child stack:\n"); printk("clone: child stack:\n");
show_stackframe(childstack); show_stackframe(childstack);
#endif #endif
childregs->u_regs[UREG_FP] = (unsigned long)childstack; childregs->u_regs[UREG_FP] = (unsigned long)childstack;
}
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -475,69 +476,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) ...@@ -475,69 +476,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
return 1; return 1;
} }
/*
* sparc_execve() executes a new program after the asm stub has set
* things up for us. This should basically do what I want it to.
*/
asmlinkage int sparc_execve(struct pt_regs *regs)
{
int error, base = 0;
struct filename *filename;
/* Check for indirect call. */
if(regs->u_regs[UREG_G1] == 0)
base = 1;
filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
error = do_execve(filename->name,
(const char __user *const __user *)
regs->u_regs[base + UREG_I1],
(const char __user *const __user *)
regs->u_regs[base + UREG_I2],
regs);
putname(filename);
out:
return error;
}
/*
* This is the mechanism for creating a new kernel thread.
*
* NOTE! Only a kernel-only process(ie the swapper or direct descendants
* who haven't done an "execve()") should use this: it will work within
* a system call from a "real" process, but the process memory space will
* not be freed until both the parent and the child have exited.
*/
pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
long retval;
__asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */
"mov %5, %%g3\n\t" /* and arg. */
"mov %1, %%g1\n\t"
"mov %2, %%o0\n\t" /* Clone flags. */
"mov 0, %%o1\n\t" /* usp arg == 0 */
"t 0x10\n\t" /* Linux/Sparc clone(). */
"cmp %%o1, 0\n\t"
"be 1f\n\t" /* The parent, just return. */
" nop\n\t" /* Delay slot. */
"jmpl %%g2, %%o7\n\t" /* Call the function. */
" mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
"mov %3, %%g1\n\t"
"t 0x10\n\t" /* Linux/Sparc exit(). */
/* Notreached by child. */
"1: mov %%o0, %0\n\t" :
"=r" (retval) :
"i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
}
EXPORT_SYMBOL(kernel_thread);
unsigned long get_wchan(struct task_struct *task) unsigned long get_wchan(struct task_struct *task)
{ {
unsigned long pc, fp, bias = 0; unsigned long pc, fp, bias = 0;
......
...@@ -538,64 +538,55 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, ...@@ -538,64 +538,55 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
* Child --> %o0 == parents pid, %o1 == 1 * Child --> %o0 == parents pid, %o1 == 1
*/ */
int copy_thread(unsigned long clone_flags, unsigned long sp, int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long unused, unsigned long arg,
struct task_struct *p, struct pt_regs *regs) struct task_struct *p, struct pt_regs *regs)
{ {
struct thread_info *t = task_thread_info(p); struct thread_info *t = task_thread_info(p);
struct sparc_stackf *parent_sf; struct sparc_stackf *parent_sf;
unsigned long child_stack_sz; unsigned long child_stack_sz;
char *child_trap_frame; char *child_trap_frame;
int kernel_thread;
kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
parent_sf = ((struct sparc_stackf *) regs) - 1;
/* Calculate offset to stack_frame & pt_regs */ /* Calculate offset to stack_frame & pt_regs */
child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
(kernel_thread ? STACKFRAME_SZ : 0));
child_trap_frame = (task_stack_page(p) + child_trap_frame = (task_stack_page(p) +
(THREAD_SIZE - child_stack_sz)); (THREAD_SIZE - child_stack_sz));
memcpy(child_trap_frame, parent_sf, child_stack_sz);
t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
(0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
(((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
t->new_child = 1; t->new_child = 1;
t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
t->kregs = (struct pt_regs *) (child_trap_frame + t->kregs = (struct pt_regs *) (child_trap_frame +
sizeof(struct sparc_stackf)); sizeof(struct sparc_stackf));
t->fpsaved[0] = 0; t->fpsaved[0] = 0;
if (kernel_thread) { if (unlikely(p->flags & PF_KTHREAD)) {
struct sparc_stackf *child_sf = (struct sparc_stackf *) memset(child_trap_frame, 0, child_stack_sz);
(child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
(current_pt_regs()->tstate + 1) & TSTATE_CWP;
/* Zero terminate the stack backtrace. */ t->current_ds = ASI_P;
child_sf->fp = NULL; t->kregs->u_regs[UREG_G1] = sp; /* function */
t->kregs->u_regs[UREG_FP] = t->kregs->u_regs[UREG_G2] = arg;
((unsigned long) child_sf) - STACK_BIAS; return 0;
}
t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); parent_sf = ((struct sparc_stackf *) regs) - 1;
t->kregs->u_regs[UREG_G6] = (unsigned long) t; memcpy(child_trap_frame, parent_sf, child_stack_sz);
t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; if (t->flags & _TIF_32BIT) {
} else { sp &= 0x00000000ffffffffUL;
if (t->flags & _TIF_32BIT) { regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
sp &= 0x00000000ffffffffUL;
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
}
t->kregs->u_regs[UREG_FP] = sp;
t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT);
if (sp != regs->u_regs[UREG_FP]) {
unsigned long csp;
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
if (!csp)
return -EFAULT;
t->kregs->u_regs[UREG_FP] = csp;
}
if (t->utraps)
t->utraps[0]++;
} }
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;
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
if (!csp)
return -EFAULT;
t->kregs->u_regs[UREG_FP] = csp;
}
if (t->utraps)
t->utraps[0]++;
/* Set the return value for the child. */ /* Set the return value for the child. */
t->kregs->u_regs[UREG_I0] = current->pid; t->kregs->u_regs[UREG_I0] = current->pid;
...@@ -610,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -610,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
return 0; return 0;
} }
/*
* This is the mechanism for creating a new kernel thread.
*
* NOTE! Only a kernel-only process(ie the swapper or direct descendants
* who haven't done an "execve()") should use this: it will work within
* a system call from a "real" process, but the process memory space will
* not be freed until both the parent and the child have exited.
*/
pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
long retval;
/* If the parent runs before fn(arg) is called by the child,
* the input registers of this function can be clobbered.
* So we stash 'fn' and 'arg' into global registers which
* will not be modified by the parent.
*/
__asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */
"mov %5, %%g3\n\t" /* Save ARG into global */
"mov %1, %%g1\n\t" /* Clone syscall nr. */
"mov %2, %%o0\n\t" /* Clone flags. */
"mov 0, %%o1\n\t" /* usp arg == 0 */
"t 0x6d\n\t" /* Linux/Sparc clone(). */
"brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
" mov %%o0, %0\n\t"
"jmpl %%g2, %%o7\n\t" /* Call the function. */
" mov %%g3, %%o0\n\t" /* Set arg in delay. */
"mov %3, %%g1\n\t"
"t 0x6d\n\t" /* Linux/Sparc exit(). */
/* Notreached by child. */
"1:" :
"=r" (retval) :
"i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
}
EXPORT_SYMBOL(kernel_thread);
typedef struct { typedef struct {
union { union {
unsigned int pr_regs[32]; unsigned int pr_regs[32];
...@@ -715,41 +667,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) ...@@ -715,41 +667,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
} }
EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_fpu);
/*
* sparc_execve() executes a new program after the asm stub has set
* things up for us. This should basically do what I want it to.
*/
asmlinkage int sparc_execve(struct pt_regs *regs)
{
int error, base = 0;
struct filename *filename;
/* User register window flush is done by entry.S */
/* Check for indirect call. */
if (regs->u_regs[UREG_G1] == 0)
base = 1;
filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename->name,
(const char __user *const __user *)
regs->u_regs[base + UREG_I1],
(const char __user *const __user *)
regs->u_regs[base + UREG_I2], regs);
putname(filename);
if (!error) {
fprs_write(0);
current_thread_info()->xfsr[0] = 0;
current_thread_info()->fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
return error;
}
unsigned long get_wchan(struct task_struct *task) unsigned long get_wchan(struct task_struct *task)
{ {
unsigned long pc, fp, bias = 0; unsigned long pc, fp, bias = 0;
......
...@@ -396,42 +396,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig, ...@@ -396,42 +396,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
return ret; return ret;
} }
/*
* sparc32_execve() executes a new program after the asm stub has set
* things up for us. This should basically do what I want it to.
*/
asmlinkage long sparc32_execve(struct pt_regs *regs)
{
int error, base = 0;
struct filename *filename;
/* User register window flush is done by entry.S */
/* Check for indirect call. */
if ((u32)regs->u_regs[UREG_G1] == 0)
base = 1;
filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = compat_do_execve(filename->name,
compat_ptr(regs->u_regs[base + UREG_I1]),
compat_ptr(regs->u_regs[base + UREG_I2]), regs);
putname(filename);
if (!error) {
fprs_write(0);
current_thread_info()->xfsr[0] = 0;
current_thread_info()->fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
return error;
}
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
asmlinkage long sys32_init_module(void __user *umod, u32 len, asmlinkage long sys32_init_module(void __user *umod, u32 len,
......
...@@ -258,27 +258,3 @@ asmlinkage int sys_getdomainname(char __user *name, int len) ...@@ -258,27 +258,3 @@ asmlinkage int sys_getdomainname(char __user *name, int len)
up_read(&uts_sem); up_read(&uts_sem);
return err; return err;
} }
/*
* Do a system call from kernel instead of calling sys_execve so we
* end up with proper pt_regs.
*/
int kernel_execve(const char *filename,
const char *const argv[],
const char *const envp[])
{
long __res;
register long __g1 __asm__ ("g1") = __NR_execve;
register long __o0 __asm__ ("o0") = (long)(filename);
register long __o1 __asm__ ("o1") = (long)(argv);
register long __o2 __asm__ ("o2") = (long)(envp);
asm volatile ("t 0x10\n\t"
"bcc 1f\n\t"
"mov %%o0, %0\n\t"
"sub %%g0, %%o0, %0\n\t"
"1:\n\t"
: "=r" (__res), "=&r" (__o0)
: "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
: "cc");
return __res;
}
...@@ -729,25 +729,3 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, ...@@ -729,25 +729,3 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
return ret; return ret;
} }
/*
* Do a system call from kernel instead of calling sys_execve so we
* end up with proper pt_regs.
*/
int kernel_execve(const char *filename,
const char *const argv[],
const char *const envp[])
{
long __res;
register long __g1 __asm__ ("g1") = __NR_execve;
register long __o0 __asm__ ("o0") = (long)(filename);
register long __o1 __asm__ ("o1") = (long)(argv);
register long __o2 __asm__ ("o2") = (long)(envp);
asm volatile ("t 0x6d\n\t"
"sub %%g0, %%o0, %0\n\t"
"movcc %%xcc, %%o0, %0\n\t"
: "=r" (__res), "=&r" (__o0)
: "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
: "cc");
return __res;
}
/* SunOS's execv() call only specifies the argv argument, the /* SunOS's execv() call only specifies the argv argument, the
* environment settings are the same as the calling processes. * environment settings are the same as the calling processes.
*/ */
sys_execve: sys64_execve:
sethi %hi(sparc_execve), %g1 set sys_execve, %g1
ba,pt %xcc, execve_merge jmpl %g1, %g0
or %g1, %lo(sparc_execve), %g1 flushw
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
sunos_execv: sunos_execv:
stx %g0, [%sp + PTREGS_OFF + PT_V9_I2] mov %g0, %o2
sys32_execve: sys32_execve:
sethi %hi(sparc32_execve), %g1 set compat_sys_execve, %g1
or %g1, %lo(sparc32_execve), %g1
#endif
execve_merge:
flushw
jmpl %g1, %g0 jmpl %g1, %g0
add %sp, PTREGS_OFF, %o0 flushw
#endif
.align 32 .align 32
sys_sparc_pipe: sys_sparc_pipe:
...@@ -112,11 +108,16 @@ sys_clone: ...@@ -112,11 +108,16 @@ sys_clone:
ret_from_syscall: ret_from_syscall:
/* Clear current_thread_info()->new_child. */ /* Clear current_thread_info()->new_child. */
stb %g0, [%g6 + TI_NEW_CHILD] stb %g0, [%g6 + TI_NEW_CHILD]
ldx [%g6 + TI_FLAGS], %l0
call schedule_tail call schedule_tail
mov %g7, %o0 mov %g7, %o0
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
brnz,pt %o0, ret_sys_call
ldx [%g6 + TI_FLAGS], %l0
ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1
call %l1
ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
ba,pt %xcc, ret_sys_call ba,pt %xcc, ret_sys_call
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 mov 0, %o0
.globl sparc_exit .globl sparc_exit
.type sparc_exit,#function .type sparc_exit,#function
...@@ -222,7 +223,6 @@ ret_sys_call: ...@@ -222,7 +223,6 @@ ret_sys_call:
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
2: 2:
stb %g0, [%g6 + TI_SYS_NOERROR]
/* System call success, clear Carry condition code. */ /* System call success, clear Carry condition code. */
andn %g3, %g2, %g3 andn %g3, %g2, %g3
3: 3:
......
...@@ -106,7 +106,7 @@ sys_call_table: ...@@ -106,7 +106,7 @@ sys_call_table:
/*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall /*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall
.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys64_execve
/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
.word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall
/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect
......
...@@ -2688,8 +2688,8 @@ void __init trap_init(void) ...@@ -2688,8 +2688,8 @@ void __init trap_init(void)
TI_PRE_COUNT != offsetof(struct thread_info, TI_PRE_COUNT != offsetof(struct thread_info,
preempt_count) || preempt_count) ||
TI_NEW_CHILD != offsetof(struct thread_info, new_child) || TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
TI_SYS_NOERROR != offsetof(struct thread_info, TI_CURRENT_DS != offsetof(struct thread_info,
syscall_noerror) || current_ds) ||
TI_RESTART_BLOCK != offsetof(struct thread_info, TI_RESTART_BLOCK != offsetof(struct thread_info,
restart_block) || restart_block) ||
TI_KUNA_REGS != offsetof(struct thread_info, TI_KUNA_REGS != offsetof(struct thread_info,
......
...@@ -624,7 +624,7 @@ static void __init inherit_prom_mappings(void) ...@@ -624,7 +624,7 @@ static void __init inherit_prom_mappings(void)
void prom_world(int enter) void prom_world(int enter)
{ {
if (!enter) if (!enter)
set_fs((mm_segment_t) { get_thread_current_ds() }); set_fs(get_fs());
__asm__ __volatile__("flushw"); __asm__ __volatile__("flushw");
} }
......
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