2005-04-17 02:20:36 +04:00
/*
2009-03-26 17:23:52 +03:00
* This file handles the architecture dependent parts of process handling .
2005-04-17 02:20:36 +04:00
*
2009-03-26 17:23:52 +03:00
* Copyright IBM Corp . 1999 , 2009
* Author ( s ) : Martin Schwidefsky < schwidefsky @ de . ibm . com > ,
* Hartmut Penner < hp @ de . ibm . com > ,
* Denis Joseph Barrow ,
2005-04-17 02:20:36 +04:00
*/
# include <linux/compiler.h>
# include <linux/cpu.h>
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/mm.h>
2007-07-30 02:36:13 +04:00
# include <linux/fs.h>
2005-04-17 02:20:36 +04:00
# include <linux/smp.h>
# include <linux/stddef.h>
# include <linux/unistd.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/user.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/reboot.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/notifier.h>
2008-01-26 16:11:01 +03:00
# include <linux/utsname.h>
2008-04-17 09:46:25 +04:00
# include <linux/tick.h>
2008-04-17 09:46:26 +04:00
# include <linux/elfcore.h>
2008-12-31 17:11:40 +03:00
# include <linux/kernel_stat.h>
2009-01-14 16:14:36 +03:00
# include <linux/syscalls.h>
2009-06-12 12:26:25 +04:00
# include <asm/compat.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/pgtable.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/processor.h>
# include <asm/irq.h>
# include <asm/timer.h>
2009-03-26 17:24:01 +03:00
# include <asm/nmi.h>
2008-04-17 09:46:26 +04:00
# include "entry.h"
2005-04-17 02:20:36 +04:00
2006-09-28 18:56:43 +04:00
asmlinkage void ret_from_fork ( void ) asm ( " ret_from_fork " ) ;
2005-04-17 02:20:36 +04:00
/*
* Return saved PC of a blocked thread . used in kernel / sched .
* resume in entry . S does not create a new stack frame , it
* just stores the registers % r6 - % r15 to the frame given by
* schedule . We want to return the address of the caller of
* schedule , so we have to walk the backchain one time to
* find the frame schedule ( ) store its return address .
*/
unsigned long thread_saved_pc ( struct task_struct * tsk )
{
2006-01-15 00:20:57 +03:00
struct stack_frame * sf , * low , * high ;
2005-04-17 02:20:36 +04:00
2006-01-15 00:20:57 +03:00
if ( ! tsk | | ! task_stack_page ( tsk ) )
return 0 ;
low = task_stack_page ( tsk ) ;
high = ( struct stack_frame * ) task_pt_regs ( tsk ) ;
sf = ( struct stack_frame * ) ( tsk - > thread . ksp & PSW_ADDR_INSN ) ;
if ( sf < = low | | sf > high )
return 0 ;
sf = ( struct stack_frame * ) ( sf - > back_chain & PSW_ADDR_INSN ) ;
if ( sf < = low | | sf > high )
return 0 ;
2005-04-17 02:20:36 +04:00
return sf - > gprs [ 8 ] ;
}
/*
* The idle loop on a S390 . . .
*/
2006-03-24 14:15:57 +03:00
static void default_idle ( void )
2005-04-17 02:20:36 +04:00
{
[PATCH] sched: resched and cpu_idle rework
Make some changes to the NEED_RESCHED and POLLING_NRFLAG to reduce
confusion, and make their semantics rigid. Improves efficiency of
resched_task and some cpu_idle routines.
* In resched_task:
- TIF_NEED_RESCHED is only cleared with the task's runqueue lock held,
and as we hold it during resched_task, then there is no need for an
atomic test and set there. The only other time this should be set is
when the task's quantum expires, in the timer interrupt - this is
protected against because the rq lock is irq-safe.
- If TIF_NEED_RESCHED is set, then we don't need to do anything. It
won't get unset until the task get's schedule()d off.
- If we are running on the same CPU as the task we resched, then set
TIF_NEED_RESCHED and no further action is required.
- If we are running on another CPU, and TIF_POLLING_NRFLAG is *not* set
after TIF_NEED_RESCHED has been set, then we need to send an IPI.
Using these rules, we are able to remove the test and set operation in
resched_task, and make clear the previously vague semantics of
POLLING_NRFLAG.
* In idle routines:
- Enter cpu_idle with preempt disabled. When the need_resched() condition
becomes true, explicitly call schedule(). This makes things a bit clearer
(IMO), but haven't updated all architectures yet.
- Many do a test and clear of TIF_NEED_RESCHED for some reason. According
to the resched_task rules, this isn't needed (and actually breaks the
assumption that TIF_NEED_RESCHED is only cleared with the runqueue lock
held). So remove that. Generally one less locked memory op when switching
to the idle thread.
- Many idle routines clear TIF_POLLING_NRFLAG, and only set it in the inner
most polling idle loops. The above resched_task semantics allow it to be
set until before the last time need_resched() is checked before going into
a halt requiring interrupt wakeup.
Many idle routines simply never enter such a halt, and so POLLING_NRFLAG
can be always left set, completely eliminating resched IPIs when rescheduling
the idle task.
POLLING_NRFLAG width can be increased, to reduce the chance of resched IPIs.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Con Kolivas <kernel@kolivas.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-11-09 08:39:04 +03:00
/* CPU is going idle. */
2005-04-17 02:20:36 +04:00
local_irq_disable ( ) ;
[PATCH] sched: resched and cpu_idle rework
Make some changes to the NEED_RESCHED and POLLING_NRFLAG to reduce
confusion, and make their semantics rigid. Improves efficiency of
resched_task and some cpu_idle routines.
* In resched_task:
- TIF_NEED_RESCHED is only cleared with the task's runqueue lock held,
and as we hold it during resched_task, then there is no need for an
atomic test and set there. The only other time this should be set is
when the task's quantum expires, in the timer interrupt - this is
protected against because the rq lock is irq-safe.
- If TIF_NEED_RESCHED is set, then we don't need to do anything. It
won't get unset until the task get's schedule()d off.
- If we are running on the same CPU as the task we resched, then set
TIF_NEED_RESCHED and no further action is required.
- If we are running on another CPU, and TIF_POLLING_NRFLAG is *not* set
after TIF_NEED_RESCHED has been set, then we need to send an IPI.
Using these rules, we are able to remove the test and set operation in
resched_task, and make clear the previously vague semantics of
POLLING_NRFLAG.
* In idle routines:
- Enter cpu_idle with preempt disabled. When the need_resched() condition
becomes true, explicitly call schedule(). This makes things a bit clearer
(IMO), but haven't updated all architectures yet.
- Many do a test and clear of TIF_NEED_RESCHED for some reason. According
to the resched_task rules, this isn't needed (and actually breaks the
assumption that TIF_NEED_RESCHED is only cleared with the runqueue lock
held). So remove that. Generally one less locked memory op when switching
to the idle thread.
- Many idle routines clear TIF_POLLING_NRFLAG, and only set it in the inner
most polling idle loops. The above resched_task semantics allow it to be
set until before the last time need_resched() is checked before going into
a halt requiring interrupt wakeup.
Many idle routines simply never enter such a halt, and so POLLING_NRFLAG
can be always left set, completely eliminating resched IPIs when rescheduling
the idle task.
POLLING_NRFLAG width can be increased, to reduce the chance of resched IPIs.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Con Kolivas <kernel@kolivas.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-11-09 08:39:04 +03:00
if ( need_resched ( ) ) {
2005-04-17 02:20:36 +04:00
local_irq_enable ( ) ;
[PATCH] sched: resched and cpu_idle rework
Make some changes to the NEED_RESCHED and POLLING_NRFLAG to reduce
confusion, and make their semantics rigid. Improves efficiency of
resched_task and some cpu_idle routines.
* In resched_task:
- TIF_NEED_RESCHED is only cleared with the task's runqueue lock held,
and as we hold it during resched_task, then there is no need for an
atomic test and set there. The only other time this should be set is
when the task's quantum expires, in the timer interrupt - this is
protected against because the rq lock is irq-safe.
- If TIF_NEED_RESCHED is set, then we don't need to do anything. It
won't get unset until the task get's schedule()d off.
- If we are running on the same CPU as the task we resched, then set
TIF_NEED_RESCHED and no further action is required.
- If we are running on another CPU, and TIF_POLLING_NRFLAG is *not* set
after TIF_NEED_RESCHED has been set, then we need to send an IPI.
Using these rules, we are able to remove the test and set operation in
resched_task, and make clear the previously vague semantics of
POLLING_NRFLAG.
* In idle routines:
- Enter cpu_idle with preempt disabled. When the need_resched() condition
becomes true, explicitly call schedule(). This makes things a bit clearer
(IMO), but haven't updated all architectures yet.
- Many do a test and clear of TIF_NEED_RESCHED for some reason. According
to the resched_task rules, this isn't needed (and actually breaks the
assumption that TIF_NEED_RESCHED is only cleared with the runqueue lock
held). So remove that. Generally one less locked memory op when switching
to the idle thread.
- Many idle routines clear TIF_POLLING_NRFLAG, and only set it in the inner
most polling idle loops. The above resched_task semantics allow it to be
set until before the last time need_resched() is checked before going into
a halt requiring interrupt wakeup.
Many idle routines simply never enter such a halt, and so POLLING_NRFLAG
can be always left set, completely eliminating resched IPIs when rescheduling
the idle task.
POLLING_NRFLAG width can be increased, to reduce the chance of resched IPIs.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Con Kolivas <kernel@kolivas.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-11-09 08:39:04 +03:00
return ;
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_HOTPLUG_CPU
2008-04-17 09:46:23 +04:00
if ( cpu_is_offline ( smp_processor_id ( ) ) ) {
2006-02-18 00:52:46 +03:00
preempt_enable_no_resched ( ) ;
2005-04-17 02:20:36 +04:00
cpu_die ( ) ;
2006-02-18 00:52:46 +03:00
}
2005-04-17 02:20:36 +04:00
# endif
2005-06-26 01:55:30 +04:00
local_mcck_disable ( ) ;
if ( test_thread_flag ( TIF_MCCK_PENDING ) ) {
local_mcck_enable ( ) ;
local_irq_enable ( ) ;
s390_handle_mcck ( ) ;
return ;
}
2006-07-03 11:24:46 +04:00
trace_hardirqs_on ( ) ;
2008-11-14 20:18:04 +03:00
/* Don't trace preempt off for idle. */
stop_critical_timings ( ) ;
2008-12-31 17:11:41 +03:00
/* Stop virtual timer and halt the cpu. */
vtime_stop_cpu ( ) ;
/* Reenable preemption tracer. */
2008-11-14 20:18:04 +03:00
start_critical_timings ( ) ;
2005-04-17 02:20:36 +04:00
}
void cpu_idle ( void )
{
2005-11-09 08:39:01 +03:00
for ( ; ; ) {
2008-07-19 11:33:21 +04:00
tick_nohz_stop_sched_tick ( 1 ) ;
2005-11-09 08:39:01 +03:00
while ( ! need_resched ( ) )
default_idle ( ) ;
2008-04-17 09:46:25 +04:00
tick_nohz_restart_sched_tick ( ) ;
2005-11-09 08:39:01 +03:00
preempt_enable_no_resched ( ) ;
schedule ( ) ;
preempt_disable ( ) ;
}
2005-04-17 02:20:36 +04:00
}
extern void kernel_thread_starter ( void ) ;
2006-09-28 18:56:43 +04:00
asm (
" .align 4 \n "
2005-04-17 02:20:36 +04:00
" kernel_thread_starter: \n "
" la 2,0(10) \n "
" basr 14,9 \n "
" la 2,0 \n "
" br 11 \n " ) ;
int kernel_thread ( int ( * fn ) ( void * ) , void * arg , unsigned long flags )
{
struct pt_regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
2007-02-05 23:18:17 +03:00
regs . psw . mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT ;
2005-04-17 02:20:36 +04:00
regs . psw . addr = ( unsigned long ) kernel_thread_starter | PSW_ADDR_AMODE ;
regs . gprs [ 9 ] = ( unsigned long ) fn ;
regs . gprs [ 10 ] = ( unsigned long ) arg ;
regs . gprs [ 11 ] = ( unsigned long ) do_exit ;
regs . orig_gpr2 = - 1 ;
/* Ok, create the new process.. */
return do_fork ( flags | CLONE_VM | CLONE_UNTRACED ,
0 , & regs , 0 , NULL , NULL ) ;
}
2009-03-26 17:24:04 +03:00
EXPORT_SYMBOL ( kernel_thread ) ;
2005-04-17 02:20:36 +04:00
/*
* Free current thread data structures etc . .
*/
void exit_thread ( void )
{
}
void flush_thread ( void )
{
clear_used_math ( ) ;
clear_tsk_thread_flag ( current , TIF_USEDFPU ) ;
}
void release_thread ( struct task_struct * dead_task )
{
}
2009-04-03 03:56:59 +04:00
int copy_thread ( unsigned long clone_flags , unsigned long new_stackp ,
2009-03-26 17:23:52 +03:00
unsigned long unused ,
struct task_struct * p , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2009-03-26 17:23:53 +03:00
struct thread_info * ti ;
2009-03-26 17:23:52 +03:00
struct fake_frame
{
struct stack_frame sf ;
struct pt_regs childregs ;
} * frame ;
frame = container_of ( task_pt_regs ( p ) , struct fake_frame , childregs ) ;
p - > thread . ksp = ( unsigned long ) frame ;
2005-04-17 02:20:36 +04:00
/* Store access registers to kernel stack of new process. */
2009-03-26 17:23:52 +03:00
frame - > childregs = * regs ;
2005-04-17 02:20:36 +04:00
frame - > childregs . gprs [ 2 ] = 0 ; /* child returns 0 on fork. */
2009-03-26 17:23:52 +03:00
frame - > childregs . gprs [ 15 ] = new_stackp ;
frame - > sf . back_chain = 0 ;
2005-04-17 02:20:36 +04:00
2009-03-26 17:23:52 +03:00
/* new return point is ret_from_fork */
frame - > sf . gprs [ 8 ] = ( unsigned long ) ret_from_fork ;
2005-04-17 02:20:36 +04:00
2009-03-26 17:23:52 +03:00
/* fake return stack for resume(), don't go back to schedule */
frame - > sf . gprs [ 9 ] = ( unsigned long ) frame ;
2005-04-17 02:20:36 +04:00
/* Save access registers to new thread structure. */
save_access_regs ( & p - > thread . acrs [ 0 ] ) ;
2006-01-06 11:19:28 +03:00
# ifndef CONFIG_64BIT
2009-03-26 17:23:52 +03:00
/*
2005-04-17 02:20:36 +04:00
* save fprs to current - > thread . fp_regs to merge them with
* the emulated registers and then copy the result to the child .
*/
save_fp_regs ( & current - > thread . fp_regs ) ;
memcpy ( & p - > thread . fp_regs , & current - > thread . fp_regs ,
sizeof ( s390_fp_regs ) ) ;
/* Set a new TLS ? */
if ( clone_flags & CLONE_SETTLS )
p - > thread . acrs [ 0 ] = regs - > gprs [ 6 ] ;
2006-01-06 11:19:28 +03:00
# else /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
/* Save the fpu registers to new thread structure. */
save_fp_regs ( & p - > thread . fp_regs ) ;
/* Set a new TLS ? */
if ( clone_flags & CLONE_SETTLS ) {
2009-06-12 12:26:25 +04:00
if ( is_compat_task ( ) ) {
2005-04-17 02:20:36 +04:00
p - > thread . acrs [ 0 ] = ( unsigned int ) regs - > gprs [ 6 ] ;
} else {
p - > thread . acrs [ 0 ] = ( unsigned int ) ( regs - > gprs [ 6 ] > > 32 ) ;
p - > thread . acrs [ 1 ] = ( unsigned int ) regs - > gprs [ 6 ] ;
}
}
2006-01-06 11:19:28 +03:00
# endif /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
/* start new process with ar4 pointing to the correct address space */
p - > thread . mm_segment = get_fs ( ) ;
2009-03-26 17:23:52 +03:00
/* Don't copy debug registers */
memset ( & p - > thread . per_info , 0 , sizeof ( p - > thread . per_info ) ) ;
2009-03-26 17:23:53 +03:00
/* Initialize per thread user and system timer values */
ti = task_thread_info ( p ) ;
ti - > user_timer = 0 ;
ti - > system_timer = 0 ;
2009-03-26 17:23:52 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 16:14:36 +03:00
SYSCALL_DEFINE0 ( fork )
2005-04-17 02:20:36 +04:00
{
2007-04-27 18:01:40 +04:00
struct pt_regs * regs = task_pt_regs ( current ) ;
return do_fork ( SIGCHLD , regs - > gprs [ 15 ] , regs , 0 , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 16:14:36 +03:00
SYSCALL_DEFINE0 ( clone )
2005-04-17 02:20:36 +04:00
{
2007-04-27 18:01:40 +04:00
struct pt_regs * regs = task_pt_regs ( current ) ;
unsigned long clone_flags ;
unsigned long newsp ;
2005-04-17 02:20:36 +04:00
int __user * parent_tidptr , * child_tidptr ;
2007-04-27 18:01:40 +04:00
clone_flags = regs - > gprs [ 3 ] ;
newsp = regs - > orig_gpr2 ;
parent_tidptr = ( int __user * ) regs - > gprs [ 4 ] ;
child_tidptr = ( int __user * ) regs - > gprs [ 5 ] ;
if ( ! newsp )
newsp = regs - > gprs [ 15 ] ;
return do_fork ( clone_flags , newsp , regs , 0 ,
2005-04-17 02:20:36 +04:00
parent_tidptr , child_tidptr ) ;
}
/*
* This is trivial , and on the face of it looks like it
* could equally well be done in user mode .
*
* Not so , for quite unobvious reasons - register pressure .
* In user mode vfork ( ) cannot have a stack frame , and if
* done by calling the " clone() " system call directly , you
* do not have enough call - clobbered registers to hold all
* the information you need .
*/
2009-01-14 16:14:36 +03:00
SYSCALL_DEFINE0 ( vfork )
2005-04-17 02:20:36 +04:00
{
2007-04-27 18:01:40 +04:00
struct pt_regs * regs = task_pt_regs ( current ) ;
2005-04-17 02:20:36 +04:00
return do_fork ( CLONE_VFORK | CLONE_VM | SIGCHLD ,
2007-04-27 18:01:40 +04:00
regs - > gprs [ 15 ] , regs , 0 , NULL , NULL ) ;
}
asmlinkage void execve_tail ( void )
{
current - > thread . fp_regs . fpc = 0 ;
if ( MACHINE_HAS_IEEE )
asm volatile ( " sfpc %0,%0 " : : " d " ( 0 ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
* sys_execve ( ) executes a new program .
*/
2009-01-14 16:14:36 +03:00
SYSCALL_DEFINE0 ( execve )
2005-04-17 02:20:36 +04:00
{
2007-04-27 18:01:40 +04:00
struct pt_regs * regs = task_pt_regs ( current ) ;
char * filename ;
unsigned long result ;
int rc ;
filename = getname ( ( char __user * ) regs - > orig_gpr2 ) ;
if ( IS_ERR ( filename ) ) {
result = PTR_ERR ( filename ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 18:01:40 +04:00
rc = do_execve ( filename , ( char __user * __user * ) regs - > gprs [ 3 ] ,
( char __user * __user * ) regs - > gprs [ 4 ] , regs ) ;
if ( rc ) {
result = rc ;
goto out_putname ;
}
execve_tail ( ) ;
result = regs - > gprs [ 2 ] ;
out_putname :
putname ( filename ) ;
2005-04-17 02:20:36 +04:00
out :
2007-04-27 18:01:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
/*
* fill in the FPU structure for a core dump .
*/
int dump_fpu ( struct pt_regs * regs , s390_fp_regs * fpregs )
{
2006-01-06 11:19:28 +03:00
# ifndef CONFIG_64BIT
2009-03-26 17:23:52 +03:00
/*
2005-04-17 02:20:36 +04:00
* save fprs to current - > thread . fp_regs to merge them with
* the emulated registers and then copy the result to the dump .
*/
save_fp_regs ( & current - > thread . fp_regs ) ;
memcpy ( fpregs , & current - > thread . fp_regs , sizeof ( s390_fp_regs ) ) ;
2006-01-06 11:19:28 +03:00
# else /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
save_fp_regs ( fpregs ) ;
2006-01-06 11:19:28 +03:00
# endif /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
return 1 ;
}
2009-03-26 17:24:04 +03:00
EXPORT_SYMBOL ( dump_fpu ) ;
2005-04-17 02:20:36 +04:00
unsigned long get_wchan ( struct task_struct * p )
{
struct stack_frame * sf , * low , * high ;
unsigned long return_address ;
int count ;
2006-01-12 12:05:50 +03:00
if ( ! p | | p = = current | | p - > state = = TASK_RUNNING | | ! task_stack_page ( p ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2006-01-12 12:05:50 +03:00
low = task_stack_page ( p ) ;
high = ( struct stack_frame * ) task_pt_regs ( p ) ;
2005-04-17 02:20:36 +04:00
sf = ( struct stack_frame * ) ( p - > thread . ksp & PSW_ADDR_INSN ) ;
if ( sf < = low | | sf > high )
return 0 ;
for ( count = 0 ; count < 16 ; count + + ) {
sf = ( struct stack_frame * ) ( sf - > back_chain & PSW_ADDR_INSN ) ;
if ( sf < = low | | sf > high )
return 0 ;
return_address = sf - > gprs [ 8 ] & PSW_ADDR_INSN ;
if ( ! in_sched_functions ( return_address ) )
return return_address ;
}
return 0 ;
}