321 lines · 7.0 KB · C
RawDownload
/* MN10300  Process handling code * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */#include <linux/module.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/reboot.h>#include <linux/percpu.h>#include <linux/err.h>#include <linux/fs.h>#include <linux/slab.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/processor.h>#include <asm/mmu_context.h>#include <asm/fpu.h>#include <asm/reset-regs.h>#include <asm/gdb-stub.h>#include "internal.h" /* * power management idle function, if any.. */void (*pm_idle)(void);EXPORT_SYMBOL(pm_idle); /* * return saved PC of a blocked thread. */unsigned long thread_saved_pc(struct task_struct *tsk){	return ((unsigned long *) tsk->thread.sp)[3];} /* * power off function, if any */void (*pm_power_off)(void);EXPORT_SYMBOL(pm_power_off); #if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)/* * we use this if we don't have any better idle routine */static void default_idle(void){	local_irq_disable();	if (!need_resched())		safe_halt();	else		local_irq_enable();} #else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU  *//* * On SMP it's slightly faster (but much more power-consuming!) * to poll the ->work.need_resched flag instead of waiting for the * cross-CPU IPI to arrive. Use this option with caution. */static inline void poll_idle(void){	int oldval; 	local_irq_enable(); 	/*	 * Deal with another CPU just having chosen a thread to	 * run here:	 */	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); 	if (!oldval) {		set_thread_flag(TIF_POLLING_NRFLAG);		while (!need_resched())			cpu_relax();		clear_thread_flag(TIF_POLLING_NRFLAG);	} else {		set_need_resched();	}}#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */ /* * the idle thread * - there's no useful work to be done, so just try to conserve power and have *   a low exit latency (ie sit in a loop waiting for somebody to say that *   they'd like to reschedule) */void cpu_idle(void){	/* endless idle loop with no priority at all */	for (;;) {		while (!need_resched()) {			void (*idle)(void); 			smp_rmb();			idle = pm_idle;			if (!idle) {#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)				idle = poll_idle;#else  /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */				idle = default_idle;#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */			}			idle();		} 		schedule_preempt_disabled();	}} void release_segments(struct mm_struct *mm){} void machine_restart(char *cmd){#ifdef CONFIG_KERNEL_DEBUGGER	gdbstub_exit(0);#endif #ifdef mn10300_unit_hard_reset	mn10300_unit_hard_reset();#else	mn10300_proc_hard_reset();#endif} void machine_halt(void){#ifdef CONFIG_KERNEL_DEBUGGER	gdbstub_exit(0);#endif} void machine_power_off(void){#ifdef CONFIG_KERNEL_DEBUGGER	gdbstub_exit(0);#endif} void show_regs(struct pt_regs *regs){} /* * create a kernel thread */int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags){	struct pt_regs regs; 	memset(&regs, 0, sizeof(regs)); 	regs.a2 = (unsigned long) fn;	regs.d2 = (unsigned long) arg;	regs.pc = (unsigned long) kernel_thread_helper;	local_save_flags(regs.epsw);	regs.epsw |= EPSW_IE | EPSW_IM_7; 	/* Ok, create the new process.. */	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,		       NULL, NULL);}EXPORT_SYMBOL(kernel_thread); /* * free current thread data structures etc.. */void exit_thread(void){	exit_fpu();} void flush_thread(void){	flush_fpu();} void release_thread(struct task_struct *dead_task){} /* * we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */void copy_segments(struct task_struct *p, struct mm_struct *new_mm){} /* * this gets called so that we can store lazy state into memory and copy the * current task into the new thread. */int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src){	unlazy_fpu(src);	*dst = *src;	return 0;} /* * set up the kernel stack for a new thread and copy arch-specific thread * control information */int copy_thread(unsigned long clone_flags,		unsigned long c_usp, unsigned long ustk_size,		struct task_struct *p, struct pt_regs *kregs){	struct thread_info *ti = task_thread_info(p);	struct pt_regs *c_uregs, *c_kregs, *uregs;	unsigned long c_ksp; 	uregs = current->thread.uregs; 	c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE; 	/* allocate the userspace exception frame and set it up */	c_ksp -= sizeof(struct pt_regs);	c_uregs = (struct pt_regs *) c_ksp; 	p->thread.uregs = c_uregs;	*c_uregs = *uregs;	c_uregs->sp = c_usp;	c_uregs->epsw &= ~EPSW_FE; /* my FPU */ 	c_ksp -= 12; /* allocate function call ABI slack */ 	/* the new TLS pointer is passed in as arg #5 to sys_clone() */	if (clone_flags & CLONE_SETTLS)		c_uregs->e2 = current_frame()->d3; 	/* set up the return kernel frame if called from kernel_thread() */	c_kregs = c_uregs;	if (kregs != uregs) {		c_ksp -= sizeof(struct pt_regs);		c_kregs = (struct pt_regs *) c_ksp;		*c_kregs = *kregs;		c_kregs->sp = c_usp;		c_kregs->next = c_uregs;#ifdef CONFIG_MN10300_CURRENT_IN_E2		c_kregs->e2 = (unsigned long) p; /* current */#endif 		c_ksp -= 12; /* allocate function call ABI slack */	} 	/* set up things up so the scheduler can start the new task */	ti->frame	= c_kregs;	p->thread.a3	= (unsigned long) c_kregs;	p->thread.sp	= c_ksp;	p->thread.pc	= (unsigned long) ret_from_fork;	p->thread.wchan	= (unsigned long) ret_from_fork;	p->thread.usp	= c_usp; 	return 0;} /* * clone a process * - tlsptr is retrieved by copy_thread() from current_frame()->d3 */asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,			  int __user *parent_tidptr, int __user *child_tidptr,			  int __user *tlsptr){	return do_fork(clone_flags, newsp ?: current_frame()->sp,		       current_frame(), 0, parent_tidptr, child_tidptr);} asmlinkage long sys_fork(void){	return do_fork(SIGCHLD, current_frame()->sp,		       current_frame(), 0, NULL, NULL);} asmlinkage long sys_vfork(void){	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, current_frame()->sp,		       current_frame(), 0, NULL, NULL);} asmlinkage long sys_execve(const char __user *name,			   const char __user *const __user *argv,			   const char __user *const __user *envp){	char *filename;	int error; 	filename = getname(name);	error = PTR_ERR(filename);	if (IS_ERR(filename))		return error;	error = do_execve(filename, argv, envp, current_frame());	putname(filename);	return error;} unsigned long get_wchan(struct task_struct *p){	return p->thread.wchan;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t