linux/arch/m68knommu/kernel/process.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/m68knommu/kernel/process.c
   3 *
   4 *  Copyright (C) 1995  Hamish Macdonald
   5 *
   6 *  68060 fixes by Jesper Skov
   7 *
   8 *  uClinux changes
   9 *  Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
  10 */
  11
  12/*
  13 * This file handles the architecture-dependent parts of process handling..
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/errno.h>
  18#include <linux/sched.h>
  19#include <linux/kernel.h>
  20#include <linux/mm.h>
  21#include <linux/smp.h>
  22#include <linux/smp_lock.h>
  23#include <linux/stddef.h>
  24#include <linux/unistd.h>
  25#include <linux/ptrace.h>
  26#include <linux/slab.h>
  27#include <linux/user.h>
  28#include <linux/interrupt.h>
  29#include <linux/reboot.h>
  30#include <linux/fs.h>
  31
  32#include <asm/uaccess.h>
  33#include <asm/system.h>
  34#include <asm/traps.h>
  35#include <asm/machdep.h>
  36#include <asm/setup.h>
  37#include <asm/pgtable.h>
  38
  39asmlinkage void ret_from_fork(void);
  40
  41/*
  42 * The following aren't currently used.
  43 */
  44void (*pm_idle)(void);
  45EXPORT_SYMBOL(pm_idle);
  46
  47void (*pm_power_off)(void);
  48EXPORT_SYMBOL(pm_power_off);
  49
  50/*
  51 * The idle loop on an m68knommu..
  52 */
  53static void default_idle(void)
  54{
  55        local_irq_disable();
  56        while (!need_resched()) {
  57                /* This stop will re-enable interrupts */
  58                __asm__("stop #0x2000" : : : "cc");
  59                local_irq_disable();
  60        }
  61        local_irq_enable();
  62}
  63
  64void (*idle)(void) = default_idle;
  65
  66/*
  67 * The idle thread. There's no useful work to be
  68 * done, so just try to conserve power and have a
  69 * low exit latency (ie sit in a loop waiting for
  70 * somebody to say that they'd like to reschedule)
  71 */
  72void cpu_idle(void)
  73{
  74        /* endless idle loop with no priority at all */
  75        while (1) {
  76                idle();
  77                preempt_enable_no_resched();
  78                schedule();
  79                preempt_disable();
  80        }
  81}
  82
  83void machine_restart(char * __unused)
  84{
  85        if (mach_reset)
  86                mach_reset();
  87        for (;;);
  88}
  89
  90void machine_halt(void)
  91{
  92        if (mach_halt)
  93                mach_halt();
  94        for (;;);
  95}
  96
  97void machine_power_off(void)
  98{
  99        if (mach_power_off)
 100                mach_power_off();
 101        for (;;);
 102}
 103
 104void show_regs(struct pt_regs * regs)
 105{
 106        printk(KERN_NOTICE "\n");
 107        printk(KERN_NOTICE "Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
 108               regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
 109        printk(KERN_NOTICE "ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
 110               regs->orig_d0, regs->d0, regs->a2, regs->a1);
 111        printk(KERN_NOTICE "A0: %08lx  D5: %08lx  D4: %08lx\n",
 112               regs->a0, regs->d5, regs->d4);
 113        printk(KERN_NOTICE "D3: %08lx  D2: %08lx  D1: %08lx\n",
 114               regs->d3, regs->d2, regs->d1);
 115        if (!(regs->sr & PS_S))
 116                printk(KERN_NOTICE "USP: %08lx\n", rdusp());
 117}
 118
 119/*
 120 * Create a kernel thread
 121 */
 122int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 123{
 124        int retval;
 125        long clone_arg = flags | CLONE_VM;
 126        mm_segment_t fs;
 127
 128        fs = get_fs();
 129        set_fs(KERNEL_DS);
 130
 131        __asm__ __volatile__ (
 132                        "movel  %%sp, %%d2\n\t"
 133                        "movel  %5, %%d1\n\t"
 134                        "movel  %1, %%d0\n\t"
 135                        "trap   #0\n\t"
 136                        "cmpl   %%sp, %%d2\n\t"
 137                        "jeq    1f\n\t"
 138                        "movel  %3, %%sp@-\n\t"
 139                        "jsr    %4@\n\t"
 140                        "movel  %2, %%d0\n\t"
 141                        "trap   #0\n"
 142                        "1:\n\t"
 143                        "movel  %%d0, %0\n"
 144                : "=d" (retval)
 145                : "i" (__NR_clone),
 146                  "i" (__NR_exit),
 147                  "a" (arg),
 148                  "a" (fn),
 149                  "a" (clone_arg)
 150                : "cc", "%d0", "%d1", "%d2");
 151
 152        set_fs(fs);
 153        return retval;
 154}
 155
 156void flush_thread(void)
 157{
 158#ifdef CONFIG_FPU
 159        unsigned long zero = 0;
 160#endif
 161        set_fs(USER_DS);
 162        current->thread.fs = __USER_DS;
 163#ifdef CONFIG_FPU
 164        if (!FPU_IS_EMU)
 165                asm volatile (".chip 68k/68881\n\t"
 166                              "frestore %0@\n\t"
 167                              ".chip 68k" : : "a" (&zero));
 168#endif
 169}
 170
 171/*
 172 * "m68k_fork()".. By the time we get here, the
 173 * non-volatile registers have also been saved on the
 174 * stack. We do some ugly pointer stuff here.. (see
 175 * also copy_thread)
 176 */
 177
 178asmlinkage int m68k_fork(struct pt_regs *regs)
 179{
 180        /* fork almost works, enough to trick you into looking elsewhere :-( */
 181        return(-EINVAL);
 182}
 183
 184asmlinkage int m68k_vfork(struct pt_regs *regs)
 185{
 186        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
 187}
 188
 189asmlinkage int m68k_clone(struct pt_regs *regs)
 190{
 191        unsigned long clone_flags;
 192        unsigned long newsp;
 193
 194        /* syscall2 puts clone_flags in d1 and usp in d2 */
 195        clone_flags = regs->d1;
 196        newsp = regs->d2;
 197        if (!newsp)
 198                newsp = rdusp();
 199        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
 200}
 201
 202int copy_thread(unsigned long clone_flags,
 203                unsigned long usp, unsigned long topstk,
 204                struct task_struct * p, struct pt_regs * regs)
 205{
 206        struct pt_regs * childregs;
 207        struct switch_stack * childstack, *stack;
 208        unsigned long *retp;
 209
 210        childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
 211
 212        *childregs = *regs;
 213        childregs->d0 = 0;
 214
 215        retp = ((unsigned long *) regs);
 216        stack = ((struct switch_stack *) retp) - 1;
 217
 218        childstack = ((struct switch_stack *) childregs) - 1;
 219        *childstack = *stack;
 220        childstack->retpc = (unsigned long)ret_from_fork;
 221
 222        p->thread.usp = usp;
 223        p->thread.ksp = (unsigned long)childstack;
 224        /*
 225         * Must save the current SFC/DFC value, NOT the value when
 226         * the parent was last descheduled - RGH  10-08-96
 227         */
 228        p->thread.fs = get_fs().seg;
 229
 230#ifdef CONFIG_FPU
 231        if (!FPU_IS_EMU) {
 232                /* Copy the current fpu state */
 233                asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
 234
 235                if (p->thread.fpstate[0])
 236                  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
 237                                "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
 238                                : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
 239                                : "memory");
 240                /* Restore the state in case the fpu was busy */
 241                asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
 242        }
 243#endif
 244
 245        return 0;
 246}
 247
 248/* Fill in the fpu structure for a core dump.  */
 249
 250int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 251{
 252#ifdef CONFIG_FPU
 253        char fpustate[216];
 254
 255        if (FPU_IS_EMU) {
 256                int i;
 257
 258                memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
 259                memcpy(fpu->fpregs, current->thread.fp, 96);
 260                /* Convert internal fpu reg representation
 261                 * into long double format
 262                 */
 263                for (i = 0; i < 24; i += 3)
 264                        fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
 265                                         ((fpu->fpregs[i] & 0x0000ffff) << 16);
 266                return 1;
 267        }
 268
 269        /* First dump the fpu context to avoid protocol violation.  */
 270        asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
 271        if (!fpustate[0])
 272                return 0;
 273
 274        asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
 275                :: "m" (fpu->fpcntl[0])
 276                : "memory");
 277        asm volatile ("fmovemx %/fp0-%/fp7,%0"
 278                :: "m" (fpu->fpregs[0])
 279                : "memory");
 280#endif
 281        return 1;
 282}
 283
 284/*
 285 *      Generic dumping code. Used for panic and debug.
 286 */
 287void dump(struct pt_regs *fp)
 288{
 289        unsigned long   *sp;
 290        unsigned char   *tp;
 291        int             i;
 292
 293        printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
 294        printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
 295
 296        if (current->mm) {
 297                printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
 298                        (int) current->mm->start_code,
 299                        (int) current->mm->end_code,
 300                        (int) current->mm->start_data,
 301                        (int) current->mm->end_data,
 302                        (int) current->mm->end_data,
 303                        (int) current->mm->brk);
 304                printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
 305                        (int) current->mm->start_stack,
 306                        (int)(((unsigned long) current) + THREAD_SIZE));
 307        }
 308
 309        printk(KERN_EMERG "PC: %08lx\n", fp->pc);
 310        printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
 311        printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 312                fp->d0, fp->d1, fp->d2, fp->d3);
 313        printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
 314                fp->d4, fp->d5, fp->a0, fp->a1);
 315        printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %08x\n",
 316                (unsigned int) rdusp(), (unsigned int) fp);
 317
 318        printk(KERN_EMERG "\nCODE:");
 319        tp = ((unsigned char *) fp->pc) - 0x20;
 320        for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
 321                if ((i % 0x10) == 0)
 322                        printk(KERN_EMERG "%08x: ", (int) (tp + i));
 323                printk("%08x ", (int) *sp++);
 324        }
 325        printk(KERN_EMERG "\n");
 326
 327        printk(KERN_EMERG "KERNEL STACK:");
 328        tp = ((unsigned char *) fp) - 0x40;
 329        for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
 330                if ((i % 0x10) == 0)
 331                        printk(KERN_EMERG "%08x: ", (int) (tp + i));
 332                printk("%08x ", (int) *sp++);
 333        }
 334        printk(KERN_EMERG "\n");
 335
 336        printk(KERN_EMERG "USER STACK:");
 337        tp = (unsigned char *) (rdusp() - 0x10);
 338        for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
 339                if ((i % 0x10) == 0)
 340                        printk(KERN_EMERG "%08x: ", (int) (tp + i));
 341                printk("%08x ", (int) *sp++);
 342        }
 343        printk(KERN_EMERG "\n");
 344}
 345
 346/*
 347 * sys_execve() executes a new program.
 348 */
 349asmlinkage int sys_execve(char *name, char **argv, char **envp)
 350{
 351        int error;
 352        char * filename;
 353        struct pt_regs *regs = (struct pt_regs *) &name;
 354
 355        lock_kernel();
 356        filename = getname(name);
 357        error = PTR_ERR(filename);
 358        if (IS_ERR(filename))
 359                goto out;
 360        error = do_execve(filename, argv, envp, regs);
 361        putname(filename);
 362out:
 363        unlock_kernel();
 364        return error;
 365}
 366
 367unsigned long get_wchan(struct task_struct *p)
 368{
 369        unsigned long fp, pc;
 370        unsigned long stack_page;
 371        int count = 0;
 372        if (!p || p == current || p->state == TASK_RUNNING)
 373                return 0;
 374
 375        stack_page = (unsigned long)p;
 376        fp = ((struct switch_stack *)p->thread.ksp)->a6;
 377        do {
 378                if (fp < stack_page+sizeof(struct thread_info) ||
 379                    fp >= THREAD_SIZE-8+stack_page)
 380                        return 0;
 381                pc = ((unsigned long *)fp)[1];
 382                if (!in_sched_functions(pc))
 383                        return pc;
 384                fp = *(unsigned long *) fp;
 385        } while (count++ < 16);
 386        return 0;
 387}
 388
 389/*
 390 * Return saved PC of a blocked thread.
 391 */
 392unsigned long thread_saved_pc(struct task_struct *tsk)
 393{
 394        struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
 395
 396        /* Check whether the thread is blocked in resume() */
 397        if (in_sched_functions(sw->retpc))
 398                return ((unsigned long *)sw->a6)[1];
 399        else
 400                return sw->retpc;
 401}
 402
 403
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.