linux/arch/h8300/kernel/process.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/h8300/kernel/process.c
   3 *
   4 * Yoshinori Sato <ysato@users.sourceforge.jp>
   5 *
   6 *  Based on:
   7 *
   8 *  linux/arch/m68knommu/kernel/process.c
   9 *
  10 *  Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
  11 *                      Kenneth Albanowski <kjahds@kjahds.com>,
  12 *                      The Silver Hammer Group, Ltd.
  13 *
  14 *  linux/arch/m68k/kernel/process.c
  15 *
  16 *  Copyright (C) 1995  Hamish Macdonald
  17 *
  18 *  68060 fixes by Jesper Skov
  19 */
  20
  21/*
  22 * This file handles the architecture-dependent parts of process handling..
  23 */
  24
  25#include <linux/errno.h>
  26#include <linux/module.h>
  27#include <linux/sched.h>
  28#include <linux/kernel.h>
  29#include <linux/mm.h>
  30#include <linux/smp.h>
  31#include <linux/smp_lock.h>
  32#include <linux/stddef.h>
  33#include <linux/unistd.h>
  34#include <linux/ptrace.h>
  35#include <linux/slab.h>
  36#include <linux/user.h>
  37#include <linux/interrupt.h>
  38#include <linux/reboot.h>
  39#include <linux/fs.h>
  40
  41#include <asm/uaccess.h>
  42#include <asm/system.h>
  43#include <asm/traps.h>
  44#include <asm/setup.h>
  45#include <asm/pgtable.h>
  46
  47void (*pm_power_off)(void) = NULL;
  48EXPORT_SYMBOL(pm_power_off);
  49
  50asmlinkage void ret_from_fork(void);
  51
  52/*
  53 * The idle loop on an H8/300..
  54 */
  55#if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
  56static void default_idle(void)
  57{
  58        local_irq_disable();
  59        if (!need_resched()) {
  60                local_irq_enable();
  61                /* XXX: race here! What if need_resched() gets set now? */
  62                __asm__("sleep");
  63        } else
  64                local_irq_enable();
  65}
  66#else
  67static void default_idle(void)
  68{
  69        cpu_relax();
  70}
  71#endif
  72void (*idle)(void) = default_idle;
  73
  74/*
  75 * The idle thread. There's no useful work to be
  76 * done, so just try to conserve power and have a
  77 * low exit latency (ie sit in a loop waiting for
  78 * somebody to say that they'd like to reschedule)
  79 */
  80void cpu_idle(void)
  81{
  82        while (1) {
  83                while (!need_resched())
  84                        idle();
  85                preempt_enable_no_resched();
  86                schedule();
  87                preempt_disable();
  88        }
  89}
  90
  91void machine_restart(char * __unused)
  92{
  93        local_irq_disable();
  94        __asm__("jmp @@0"); 
  95}
  96
  97void machine_halt(void)
  98{
  99        local_irq_disable();
 100        __asm__("sleep");
 101        for (;;);
 102}
 103
 104void machine_power_off(void)
 105{
 106        local_irq_disable();
 107        __asm__("sleep");
 108        for (;;);
 109}
 110
 111void show_regs(struct pt_regs * regs)
 112{
 113        printk("\nPC: %08lx  Status: %02x",
 114               regs->pc, regs->ccr);
 115        printk("\nORIG_ER0: %08lx ER0: %08lx ER1: %08lx",
 116               regs->orig_er0, regs->er0, regs->er1);
 117        printk("\nER2: %08lx ER3: %08lx ER4: %08lx ER5: %08lx",
 118               regs->er2, regs->er3, regs->er4, regs->er5);
 119        printk("\nER6' %08lx ",regs->er6);
 120        if (user_mode(regs))
 121                printk("USP: %08lx\n", rdusp());
 122        else
 123                printk("\n");
 124}
 125
 126/*
 127 * Create a kernel thread
 128 */
 129int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 130{
 131        long retval;
 132        long clone_arg;
 133        mm_segment_t fs;
 134
 135        fs = get_fs();
 136        set_fs (KERNEL_DS);
 137        clone_arg = flags | CLONE_VM;
 138        __asm__("mov.l sp,er3\n\t"
 139                "sub.l er2,er2\n\t"
 140                "mov.l %2,er1\n\t"
 141                "mov.l %1,er0\n\t"
 142                "trapa #0\n\t"
 143                "cmp.l sp,er3\n\t"
 144                "beq 1f\n\t"
 145                "mov.l %4,er0\n\t"
 146                "mov.l %3,er1\n\t"
 147                "jsr @er1\n\t"
 148                "mov.l %5,er0\n\t"
 149                "trapa #0\n"
 150                "1:\n\t"
 151                "mov.l er0,%0"
 152                :"=r"(retval)
 153                :"i"(__NR_clone),"g"(clone_arg),"g"(fn),"g"(arg),"i"(__NR_exit)
 154                :"er0","er1","er2","er3");
 155        set_fs (fs);
 156        return retval;
 157}
 158
 159void flush_thread(void)
 160{
 161}
 162
 163/*
 164 * "h8300_fork()".. By the time we get here, the
 165 * non-volatile registers have also been saved on the
 166 * stack. We do some ugly pointer stuff here.. (see
 167 * also copy_thread)
 168 */
 169
 170asmlinkage int h8300_fork(struct pt_regs *regs)
 171{
 172        return -EINVAL;
 173}
 174
 175asmlinkage int h8300_vfork(struct pt_regs *regs)
 176{
 177        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
 178}
 179
 180asmlinkage int h8300_clone(struct pt_regs *regs)
 181{
 182        unsigned long clone_flags;
 183        unsigned long newsp;
 184
 185        /* syscall2 puts clone_flags in er1 and usp in er2 */
 186        clone_flags = regs->er1;
 187        newsp = regs->er2;
 188        if (!newsp)
 189                newsp  = rdusp();
 190        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
 191
 192}
 193
 194int copy_thread(unsigned long clone_flags,
 195                unsigned long usp, unsigned long topstk,
 196                 struct task_struct * p, struct pt_regs * regs)
 197{
 198        struct pt_regs * childregs;
 199
 200        childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
 201
 202        *childregs = *regs;
 203        childregs->retpc = (unsigned long) ret_from_fork;
 204        childregs->er0 = 0;
 205
 206        p->thread.usp = usp;
 207        p->thread.ksp = (unsigned long)childregs;
 208
 209        return 0;
 210}
 211
 212/*
 213 * sys_execve() executes a new program.
 214 */
 215asmlinkage int sys_execve(char *name, char **argv, char **envp,int dummy,...)
 216{
 217        int error;
 218        char * filename;
 219        struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
 220
 221        lock_kernel();
 222        filename = getname(name);
 223        error = PTR_ERR(filename);
 224        if (IS_ERR(filename))
 225                goto out;
 226        error = do_execve(filename, argv, envp, regs);
 227        putname(filename);
 228out:
 229        unlock_kernel();
 230        return error;
 231}
 232
 233unsigned long thread_saved_pc(struct task_struct *tsk)
 234{
 235        return ((struct pt_regs *)tsk->thread.esp0)->pc;
 236}
 237
 238unsigned long get_wchan(struct task_struct *p)
 239{
 240        unsigned long fp, pc;
 241        unsigned long stack_page;
 242        int count = 0;
 243        if (!p || p == current || p->state == TASK_RUNNING)
 244                return 0;
 245
 246        stack_page = (unsigned long)p;
 247        fp = ((struct pt_regs *)p->thread.ksp)->er6;
 248        do {
 249                if (fp < stack_page+sizeof(struct thread_info) ||
 250                    fp >= 8184+stack_page)
 251                        return 0;
 252                pc = ((unsigned long *)fp)[1];
 253                if (!in_sched_functions(pc))
 254                        return pc;
 255                fp = *(unsigned long *) fp;
 256        } while (count++ < 16);
 257        return 0;
 258}
 259