linux/arch/mn10300/kernel/process.c
<<
>>
Prefs
   1/* MN10300  Process handling code
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11#include <linux/module.h>
  12#include <linux/errno.h>
  13#include <linux/sched.h>
  14#include <linux/kernel.h>
  15#include <linux/mm.h>
  16#include <linux/smp.h>
  17#include <linux/smp_lock.h>
  18#include <linux/stddef.h>
  19#include <linux/unistd.h>
  20#include <linux/ptrace.h>
  21#include <linux/slab.h>
  22#include <linux/user.h>
  23#include <linux/interrupt.h>
  24#include <linux/delay.h>
  25#include <linux/reboot.h>
  26#include <linux/percpu.h>
  27#include <linux/err.h>
  28#include <linux/fs.h>
  29#include <asm/uaccess.h>
  30#include <asm/pgtable.h>
  31#include <asm/system.h>
  32#include <asm/io.h>
  33#include <asm/processor.h>
  34#include <asm/mmu_context.h>
  35#include <asm/fpu.h>
  36#include <asm/reset-regs.h>
  37#include <asm/gdb-stub.h>
  38#include "internal.h"
  39
  40/*
  41 * power management idle function, if any..
  42 */
  43void (*pm_idle)(void);
  44EXPORT_SYMBOL(pm_idle);
  45
  46/*
  47 * return saved PC of a blocked thread.
  48 */
  49unsigned long thread_saved_pc(struct task_struct *tsk)
  50{
  51        return ((unsigned long *) tsk->thread.sp)[3];
  52}
  53
  54/*
  55 * power off function, if any
  56 */
  57void (*pm_power_off)(void);
  58EXPORT_SYMBOL(pm_power_off);
  59
  60/*
  61 * we use this if we don't have any better idle routine
  62 */
  63static void default_idle(void)
  64{
  65        local_irq_disable();
  66        if (!need_resched())
  67                safe_halt();
  68        else
  69                local_irq_enable();
  70}
  71
  72/*
  73 * the idle thread
  74 * - there's no useful work to be done, so just try to conserve power and have
  75 *   a low exit latency (ie sit in a loop waiting for somebody to say that
  76 *   they'd like to reschedule)
  77 */
  78void cpu_idle(void)
  79{
  80        int cpu = smp_processor_id();
  81
  82        /* endless idle loop with no priority at all */
  83        for (;;) {
  84                while (!need_resched()) {
  85                        void (*idle)(void);
  86
  87                        smp_rmb();
  88                        idle = pm_idle;
  89                        if (!idle)
  90                                idle = default_idle;
  91
  92                        irq_stat[cpu].idle_timestamp = jiffies;
  93                        idle();
  94                }
  95
  96                preempt_enable_no_resched();
  97                schedule();
  98                preempt_disable();
  99        }
 100}
 101
 102void release_segments(struct mm_struct *mm)
 103{
 104}
 105
 106void machine_restart(char *cmd)
 107{
 108#ifdef CONFIG_GDBSTUB
 109        gdbstub_exit(0);
 110#endif
 111
 112#ifdef mn10300_unit_hard_reset
 113        mn10300_unit_hard_reset();
 114#else
 115        mn10300_proc_hard_reset();
 116#endif
 117}
 118
 119void machine_halt(void)
 120{
 121#ifdef CONFIG_GDBSTUB
 122        gdbstub_exit(0);
 123#endif
 124}
 125
 126void machine_power_off(void)
 127{
 128#ifdef CONFIG_GDBSTUB
 129        gdbstub_exit(0);
 130#endif
 131}
 132
 133void show_regs(struct pt_regs *regs)
 134{
 135}
 136
 137/*
 138 * create a kernel thread
 139 */
 140int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 141{
 142        struct pt_regs regs;
 143
 144        memset(&regs, 0, sizeof(regs));
 145
 146        regs.a2 = (unsigned long) fn;
 147        regs.d2 = (unsigned long) arg;
 148        regs.pc = (unsigned long) kernel_thread_helper;
 149        local_save_flags(regs.epsw);
 150        regs.epsw |= EPSW_IE | EPSW_IM_7;
 151
 152        /* Ok, create the new process.. */
 153        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,
 154                       NULL, NULL);
 155}
 156EXPORT_SYMBOL(kernel_thread);
 157
 158/*
 159 * free current thread data structures etc..
 160 */
 161void exit_thread(void)
 162{
 163        exit_fpu();
 164}
 165
 166void flush_thread(void)
 167{
 168        flush_fpu();
 169}
 170
 171void release_thread(struct task_struct *dead_task)
 172{
 173}
 174
 175/*
 176 * we do not have to muck with descriptors here, that is
 177 * done in switch_mm() as needed.
 178 */
 179void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
 180{
 181}
 182
 183/*
 184 * this gets called before we allocate a new thread and copy the current task
 185 * into it so that we can store lazy state into memory
 186 */
 187void prepare_to_copy(struct task_struct *tsk)
 188{
 189        unlazy_fpu(tsk);
 190}
 191
 192/*
 193 * set up the kernel stack for a new thread and copy arch-specific thread
 194 * control information
 195 */
 196int copy_thread(int nr, unsigned long clone_flags,
 197                unsigned long c_usp, unsigned long ustk_size,
 198                struct task_struct *p, struct pt_regs *kregs)
 199{
 200        struct pt_regs *c_uregs, *c_kregs, *uregs;
 201        unsigned long c_ksp;
 202
 203        uregs = current->thread.uregs;
 204
 205        c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE;
 206
 207        /* allocate the userspace exception frame and set it up */
 208        c_ksp -= sizeof(struct pt_regs);
 209        c_uregs = (struct pt_regs *) c_ksp;
 210
 211        p->thread.uregs = c_uregs;
 212        *c_uregs = *uregs;
 213        c_uregs->sp = c_usp;
 214        c_uregs->epsw &= ~EPSW_FE; /* my FPU */
 215
 216        c_ksp -= 12; /* allocate function call ABI slack */
 217
 218        /* the new TLS pointer is passed in as arg #5 to sys_clone() */
 219        if (clone_flags & CLONE_SETTLS)
 220                c_uregs->e2 = __frame->d3;
 221
 222        /* set up the return kernel frame if called from kernel_thread() */
 223        c_kregs = c_uregs;
 224        if (kregs != uregs) {
 225                c_ksp -= sizeof(struct pt_regs);
 226                c_kregs = (struct pt_regs *) c_ksp;
 227                *c_kregs = *kregs;
 228                c_kregs->sp = c_usp;
 229                c_kregs->next = c_uregs;
 230#ifdef CONFIG_MN10300_CURRENT_IN_E2
 231                c_kregs->e2 = (unsigned long) p; /* current */
 232#endif
 233
 234                c_ksp -= 12; /* allocate function call ABI slack */
 235        }
 236
 237        /* set up things up so the scheduler can start the new task */
 238        p->thread.__frame = c_kregs;
 239        p->thread.a3    = (unsigned long) c_kregs;
 240        p->thread.sp    = c_ksp;
 241        p->thread.pc    = (unsigned long) ret_from_fork;
 242        p->thread.wchan = (unsigned long) ret_from_fork;
 243        p->thread.usp   = c_usp;
 244
 245        return 0;
 246}
 247
 248/*
 249 * clone a process
 250 * - tlsptr is retrieved by copy_thread() from __frame->d3
 251 */
 252asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
 253                          int __user *parent_tidptr, int __user *child_tidptr,
 254                          int __user *tlsptr)
 255{
 256        return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0,
 257                       parent_tidptr, child_tidptr);
 258}
 259
 260asmlinkage long sys_fork(void)
 261{
 262        return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL);
 263}
 264
 265asmlinkage long sys_vfork(void)
 266{
 267        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame,
 268                       0, NULL, NULL);
 269}
 270
 271asmlinkage long sys_execve(char __user *name,
 272                           char __user * __user *argv,
 273                           char __user * __user *envp)
 274{
 275        char *filename;
 276        int error;
 277
 278        lock_kernel();
 279
 280        filename = getname(name);
 281        error = PTR_ERR(filename);
 282        if (!IS_ERR(filename)) {
 283                error = do_execve(filename, argv, envp, __frame);
 284                if (error == 0)
 285                        current->ptrace &= ~PT_DTRACE;
 286
 287                putname(filename);
 288        }
 289
 290        unlock_kernel();
 291        return error;
 292}
 293
 294unsigned long get_wchan(struct task_struct *p)
 295{
 296        return p->thread.wchan;
 297}
 298