Path: blob/master/arch/cris/arch-v10/kernel/process.c
15125 views
/*1* linux/arch/cris/kernel/process.c2*3* Copyright (C) 1995 Linus Torvalds4* Copyright (C) 2000-2002 Axis Communications AB5*6* Authors: Bjorn Wesen ([email protected])7* Mikael Starvik ([email protected])8*9* This file handles the architecture-dependent parts of process handling..10*/1112#include <linux/sched.h>13#include <linux/slab.h>14#include <linux/err.h>15#include <linux/fs.h>16#include <arch/svinto.h>17#include <linux/init.h>1819#ifdef CONFIG_ETRAX_GPIO20void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */21#endif2223/*24* We use this if we don't have any better25* idle routine..26*/27void default_idle(void)28{29#ifdef CONFIG_ETRAX_GPIO30etrax_gpio_wake_up_check();31#endif32}3334/*35* Free current thread data structures etc..36*/3738void exit_thread(void)39{40/* Nothing needs to be done. */41}4243/* if the watchdog is enabled, we can simply disable interrupts and go44* into an eternal loop, and the watchdog will reset the CPU after 0.1s45* if on the other hand the watchdog wasn't enabled, we just enable it and wait46*/4748void hard_reset_now (void)49{50/*51* Don't declare this variable elsewhere. We don't want any other52* code to know about it than the watchdog handler in entry.S and53* this code, implementing hard reset through the watchdog.54*/55#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)56extern int cause_of_death;57#endif5859printk("*** HARD RESET ***\n");60local_irq_disable();6162#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)63cause_of_death = 0xbedead;64#else65/* Since we dont plan to keep on resetting the watchdog,66the key can be arbitrary hence three */67*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) |68IO_STATE(R_WATCHDOG, enable, start);69#endif7071while(1) /* waiting for RETRIBUTION! */ ;72}7374/*75* Return saved PC of a blocked thread.76*/77unsigned long thread_saved_pc(struct task_struct *t)78{79return task_pt_regs(t)->irp;80}8182static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)83{84fn(arg);85do_exit(-1); /* Should never be called, return bad exit value */86}8788/*89* Create a kernel thread90*/91int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)92{93struct pt_regs regs;9495memset(®s, 0, sizeof(regs));9697/* Don't use r10 since that is set to 0 in copy_thread */98regs.r11 = (unsigned long)fn;99regs.r12 = (unsigned long)arg;100regs.irp = (unsigned long)kernel_thread_helper;101regs.dccr = 1 << I_DCCR_BITNR;102103/* Ok, create the new process.. */104return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);105}106107/* setup the child's kernel stack with a pt_regs and switch_stack on it.108* it will be un-nested during _resume and _ret_from_sys_call when the109* new thread is scheduled.110*111* also setup the thread switching structure which is used to keep112* thread-specific data during _resumes.113*114*/115asmlinkage void ret_from_fork(void);116117int copy_thread(unsigned long clone_flags, unsigned long usp,118unsigned long unused,119struct task_struct *p, struct pt_regs *regs)120{121struct pt_regs * childregs;122struct switch_stack *swstack;123124/* put the pt_regs structure at the end of the new kernel stack page and fix it up125* remember that the task_struct doubles as the kernel stack for the task126*/127128childregs = task_pt_regs(p);129130*childregs = *regs; /* struct copy of pt_regs */131132p->set_child_tid = p->clear_child_tid = NULL;133134childregs->r10 = 0; /* child returns 0 after a fork/clone */135136/* put the switch stack right below the pt_regs */137138swstack = ((struct switch_stack *)childregs) - 1;139140swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */141142/* we want to return into ret_from_sys_call after the _resume */143144swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */145146/* fix the user-mode stackpointer */147148p->thread.usp = usp;149150/* and the kernel-mode one */151152p->thread.ksp = (unsigned long) swstack;153154#ifdef DEBUG155printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs);156show_registers(childregs);157#endif158159return 0;160}161162/*163* Be aware of the "magic" 7th argument in the four system-calls below.164* They need the latest stackframe, which is put as the 7th argument by165* entry.S. The previous arguments are dummies or actually used, but need166* to be defined to reach the 7th argument.167*168* N.B.: Another method to get the stackframe is to use current_regs(). But169* it returns the latest stack-frame stacked when going from _user mode_ and170* some of these (at least sys_clone) are called from kernel-mode sometimes171* (for example during kernel_thread, above) and thus cannot use it. Thus,172* to be sure not to get any surprises, we use the method for the other calls173* as well.174*/175176asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,177struct pt_regs *regs)178{179return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);180}181182/* if newusp is 0, we just grab the old usp */183/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */184asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,185int* parent_tid, int* child_tid, long mof, long srp,186struct pt_regs *regs)187{188if (!newusp)189newusp = rdusp();190return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);191}192193/* vfork is a system call in i386 because of register-pressure - maybe194* we can remove it and handle it in libc but we put it here until then.195*/196197asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,198struct pt_regs *regs)199{200return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);201}202203/*204* sys_execve() executes a new program.205*/206asmlinkage int sys_execve(const char *fname,207const char *const *argv,208const char *const *envp,209long r13, long mof, long srp,210struct pt_regs *regs)211{212int error;213char *filename;214215filename = getname(fname);216error = PTR_ERR(filename);217218if (IS_ERR(filename))219goto out;220error = do_execve(filename, argv, envp, regs);221putname(filename);222out:223return error;224}225226unsigned long get_wchan(struct task_struct *p)227{228#if 0229/* YURGH. TODO. */230231unsigned long ebp, esp, eip;232unsigned long stack_page;233int count = 0;234if (!p || p == current || p->state == TASK_RUNNING)235return 0;236stack_page = (unsigned long)p;237esp = p->thread.esp;238if (!stack_page || esp < stack_page || esp > 8188+stack_page)239return 0;240/* include/asm-i386/system.h:switch_to() pushes ebp last. */241ebp = *(unsigned long *) esp;242do {243if (ebp < stack_page || ebp > 8184+stack_page)244return 0;245eip = *(unsigned long *) (ebp+4);246if (!in_sched_functions(eip))247return eip;248ebp = *(unsigned long *) ebp;249} while (count++ < 16);250#endif251return 0;252}253#undef last_sched254#undef first_sched255256void show_regs(struct pt_regs * regs)257{258unsigned long usp = rdusp();259printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",260regs->irp, regs->srp, regs->dccr, usp, regs->mof );261printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",262regs->r0, regs->r1, regs->r2, regs->r3);263printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",264regs->r4, regs->r5, regs->r6, regs->r7);265printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",266regs->r8, regs->r9, regs->r10, regs->r11);267printk("r12: %08lx r13: %08lx oR10: %08lx\n",268regs->r12, regs->r13, regs->orig_r10);269}270271272273