linux/arch/frv/kernel/process.c
<<
>>
Prefs
   1/* process.c: FRV specific parts of process handling
   2 *
   3 * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 * - Derived from arch/m68k/kernel/process.c
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version
  10 * 2 of the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/errno.h>
  15#include <linux/sched.h>
  16#include <linux/kernel.h>
  17#include <linux/mm.h>
  18#include <linux/smp.h>
  19#include <linux/smp_lock.h>
  20#include <linux/stddef.h>
  21#include <linux/unistd.h>
  22#include <linux/ptrace.h>
  23#include <linux/slab.h>
  24#include <linux/user.h>
  25#include <linux/elf.h>
  26#include <linux/reboot.h>
  27#include <linux/interrupt.h>
  28#include <linux/pagemap.h>
  29
  30#include <asm/asm-offsets.h>
  31#include <asm/uaccess.h>
  32#include <asm/system.h>
  33#include <asm/setup.h>
  34#include <asm/pgtable.h>
  35#include <asm/tlb.h>
  36#include <asm/gdb-stub.h>
  37#include <asm/mb-regs.h>
  38
  39#include "local.h"
  40
  41asmlinkage void ret_from_fork(void);
  42
  43#include <asm/pgalloc.h>
  44
  45void (*pm_power_off)(void);
  46EXPORT_SYMBOL(pm_power_off);
  47
  48struct task_struct *alloc_task_struct(void)
  49{
  50        struct task_struct *p = kmalloc(THREAD_SIZE, GFP_KERNEL);
  51        if (p)
  52                atomic_set((atomic_t *)(p+1), 1);
  53        return p;
  54}
  55
  56void free_task_struct(struct task_struct *p)
  57{
  58        if (atomic_dec_and_test((atomic_t *)(p+1)))
  59                kfree(p);
  60}
  61
  62static void core_sleep_idle(void)
  63{
  64#ifdef LED_DEBUG_SLEEP
  65        /* Show that we're sleeping... */
  66        __set_LEDS(0x55aa);
  67#endif
  68        frv_cpu_core_sleep();
  69#ifdef LED_DEBUG_SLEEP
  70        /* ... and that we woke up */
  71        __set_LEDS(0);
  72#endif
  73        mb();
  74}
  75
  76void (*idle)(void) = core_sleep_idle;
  77
  78/*
  79 * The idle thread. There's no useful work to be
  80 * done, so just try to conserve power and have a
  81 * low exit latency (ie sit in a loop waiting for
  82 * somebody to say that they'd like to reschedule)
  83 */
  84void cpu_idle(void)
  85{
  86        int cpu = smp_processor_id();
  87
  88        /* endless idle loop with no priority at all */
  89        while (1) {
  90                while (!need_resched()) {
  91                        irq_stat[cpu].idle_timestamp = jiffies;
  92
  93                        check_pgt_cache();
  94
  95                        if (!frv_dma_inprogress && idle)
  96                                idle();
  97                }
  98
  99                preempt_enable_no_resched();
 100                schedule();
 101                preempt_disable();
 102        }
 103}
 104
 105void machine_restart(char * __unused)
 106{
 107        unsigned long reset_addr;
 108#ifdef CONFIG_GDBSTUB
 109        gdbstub_exit(0);
 110#endif
 111
 112        if (PSR_IMPLE(__get_PSR()) == PSR_IMPLE_FR551)
 113                reset_addr = 0xfefff500;
 114        else
 115                reset_addr = 0xfeff0500;
 116
 117        /* Software reset. */
 118        asm volatile("      dcef @(gr0,gr0),1 ! membar !"
 119                     "      sti     %1,@(%0,0) !"
 120                     "      nop ! nop ! nop ! nop ! nop ! "
 121                     "      nop ! nop ! nop ! nop ! nop ! "
 122                     "      nop ! nop ! nop ! nop ! nop ! "
 123                     "      nop ! nop ! nop ! nop ! nop ! "
 124                     : : "r" (reset_addr), "r" (1) );
 125
 126        for (;;)
 127                ;
 128}
 129
 130void machine_halt(void)
 131{
 132#ifdef CONFIG_GDBSTUB
 133        gdbstub_exit(0);
 134#endif
 135
 136        for (;;);
 137}
 138
 139void machine_power_off(void)
 140{
 141#ifdef CONFIG_GDBSTUB
 142        gdbstub_exit(0);
 143#endif
 144
 145        for (;;);
 146}
 147
 148void flush_thread(void)
 149{
 150#if 0 //ndef NO_FPU
 151        unsigned long zero = 0;
 152#endif
 153        set_fs(USER_DS);
 154}
 155
 156inline unsigned long user_stack(const struct pt_regs *regs)
 157{
 158        while (regs->next_frame)
 159                regs = regs->next_frame;
 160        return user_mode(regs) ? regs->sp : 0;
 161}
 162
 163asmlinkage int sys_fork(void)
 164{
 165#ifndef CONFIG_MMU
 166        /* fork almost works, enough to trick you into looking elsewhere:-( */
 167        return -EINVAL;
 168#else
 169        return do_fork(SIGCHLD, user_stack(__frame), __frame, 0, NULL, NULL);
 170#endif
 171}
 172
 173asmlinkage int sys_vfork(void)
 174{
 175        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, user_stack(__frame), __frame, 0,
 176                       NULL, NULL);
 177}
 178
 179/*****************************************************************************/
 180/*
 181 * clone a process
 182 * - tlsptr is retrieved by copy_thread()
 183 */
 184asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
 185                         int __user *parent_tidptr, int __user *child_tidptr,
 186                         int __user *tlsptr)
 187{
 188        if (!newsp)
 189                newsp = user_stack(__frame);
 190        return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr);
 191} /* end sys_clone() */
 192
 193/*****************************************************************************/
 194/*
 195 * This gets called before we allocate a new thread and copy
 196 * the current task into it.
 197 */
 198void prepare_to_copy(struct task_struct *tsk)
 199{
 200        //unlazy_fpu(tsk);
 201} /* end prepare_to_copy() */
 202
 203/*****************************************************************************/
 204/*
 205 * set up the kernel stack and exception frames for a new process
 206 */
 207int copy_thread(int nr, unsigned long clone_flags,
 208                unsigned long usp, unsigned long topstk,
 209                struct task_struct *p, struct pt_regs *regs)
 210{
 211        struct pt_regs *childregs0, *childregs, *regs0;
 212
 213        regs0 = __kernel_frame0_ptr;
 214        childregs0 = (struct pt_regs *)
 215                (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
 216        childregs = childregs0;
 217
 218        /* set up the userspace frame (the only place that the USP is stored) */
 219        *childregs0 = *regs0;
 220
 221        childregs0->gr8         = 0;
 222        childregs0->sp          = usp;
 223        childregs0->next_frame  = NULL;
 224
 225        /* set up the return kernel frame if called from kernel_thread() */
 226        if (regs != regs0) {
 227                childregs--;
 228                *childregs = *regs;
 229                childregs->sp = (unsigned long) childregs0;
 230                childregs->next_frame = childregs0;
 231                childregs->gr15 = (unsigned long) task_thread_info(p);
 232                childregs->gr29 = (unsigned long) p;
 233        }
 234
 235        p->set_child_tid = p->clear_child_tid = NULL;
 236
 237        p->thread.frame  = childregs;
 238        p->thread.curr   = p;
 239        p->thread.sp     = (unsigned long) childregs;
 240        p->thread.fp     = 0;
 241        p->thread.lr     = 0;
 242        p->thread.pc     = (unsigned long) ret_from_fork;
 243        p->thread.frame0 = childregs0;
 244
 245        /* the new TLS pointer is passed in as arg #5 to sys_clone() */
 246        if (clone_flags & CLONE_SETTLS)
 247                childregs->gr29 = childregs->gr12;
 248
 249        save_user_regs(p->thread.user);
 250
 251        return 0;
 252} /* end copy_thread() */
 253
 254/*
 255 * sys_execve() executes a new program.
 256 */
 257asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
 258{
 259        int error;
 260        char * filename;
 261
 262        lock_kernel();
 263        filename = getname(name);
 264        error = PTR_ERR(filename);
 265        if (IS_ERR(filename))
 266                goto out;
 267        error = do_execve(filename, argv, envp, __frame);
 268        putname(filename);
 269 out:
 270        unlock_kernel();
 271        return error;
 272}
 273
 274unsigned long get_wchan(struct task_struct *p)
 275{
 276        struct pt_regs *regs0;
 277        unsigned long fp, pc;
 278        unsigned long stack_limit;
 279        int count = 0;
 280        if (!p || p == current || p->state == TASK_RUNNING)
 281                return 0;
 282
 283        stack_limit = (unsigned long) (p + 1);
 284        fp = p->thread.fp;
 285        regs0 = p->thread.frame0;
 286
 287        do {
 288                if (fp < stack_limit || fp >= (unsigned long) regs0 || fp & 3)
 289                        return 0;
 290
 291                pc = ((unsigned long *) fp)[2];
 292
 293                /* FIXME: This depends on the order of these functions. */
 294                if (!in_sched_functions(pc))
 295                        return pc;
 296
 297                fp = *(unsigned long *) fp;
 298        } while (count++ < 16);
 299
 300        return 0;
 301}
 302
 303unsigned long thread_saved_pc(struct task_struct *tsk)
 304{
 305        /* Check whether the thread is blocked in resume() */
 306        if (in_sched_functions(tsk->thread.pc))
 307                return ((unsigned long *)tsk->thread.fp)[2];
 308        else
 309                return tsk->thread.pc;
 310}
 311
 312int elf_check_arch(const struct elf32_hdr *hdr)
 313{
 314        unsigned long hsr0 = __get_HSR(0);
 315        unsigned long psr = __get_PSR();
 316
 317        if (hdr->e_machine != EM_FRV)
 318                return 0;
 319
 320        switch (hdr->e_flags & EF_FRV_GPR_MASK) {
 321        case EF_FRV_GPR64:
 322                if ((hsr0 & HSR0_GRN) == HSR0_GRN_32)
 323                        return 0;
 324        case EF_FRV_GPR32:
 325        case 0:
 326                break;
 327        default:
 328                return 0;
 329        }
 330
 331        switch (hdr->e_flags & EF_FRV_FPR_MASK) {
 332        case EF_FRV_FPR64:
 333                if ((hsr0 & HSR0_FRN) == HSR0_FRN_32)
 334                        return 0;
 335        case EF_FRV_FPR32:
 336        case EF_FRV_FPR_NONE:
 337        case 0:
 338                break;
 339        default:
 340                return 0;
 341        }
 342
 343        if ((hdr->e_flags & EF_FRV_MULADD) == EF_FRV_MULADD)
 344                if (PSR_IMPLE(psr) != PSR_IMPLE_FR405 &&
 345                    PSR_IMPLE(psr) != PSR_IMPLE_FR451)
 346                        return 0;
 347
 348        switch (hdr->e_flags & EF_FRV_CPU_MASK) {
 349        case EF_FRV_CPU_GENERIC:
 350                break;
 351        case EF_FRV_CPU_FR300:
 352        case EF_FRV_CPU_SIMPLE:
 353        case EF_FRV_CPU_TOMCAT:
 354        default:
 355                return 0;
 356        case EF_FRV_CPU_FR400:
 357                if (PSR_IMPLE(psr) != PSR_IMPLE_FR401 &&
 358                    PSR_IMPLE(psr) != PSR_IMPLE_FR405 &&
 359                    PSR_IMPLE(psr) != PSR_IMPLE_FR451 &&
 360                    PSR_IMPLE(psr) != PSR_IMPLE_FR551)
 361                        return 0;
 362                break;
 363        case EF_FRV_CPU_FR450:
 364                if (PSR_IMPLE(psr) != PSR_IMPLE_FR451)
 365                        return 0;
 366                break;
 367        case EF_FRV_CPU_FR500:
 368                if (PSR_IMPLE(psr) != PSR_IMPLE_FR501)
 369                        return 0;
 370                break;
 371        case EF_FRV_CPU_FR550:
 372                if (PSR_IMPLE(psr) != PSR_IMPLE_FR551)
 373                        return 0;
 374                break;
 375        }
 376
 377        return 1;
 378}
 379
 380int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 381{
 382        memcpy(fpregs,
 383               &current->thread.user->f,
 384               sizeof(current->thread.user->f));
 385        return 1;
 386}
 387
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.