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/user.h>
  27#include <linux/interrupt.h>
  28#include <linux/reboot.h>
  29#include <linux/fs.h>
  30#include <linux/slab.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        if (clone_flags & CLONE_SETTLS)
 226                task_thread_info(p)->tp_value = regs->d5;
 227
 228        /*
 229         * Must save the current SFC/DFC value, NOT the value when
 230         * the parent was last descheduled - RGH  10-08-96
 231         */
 232        p->thread.fs = get_fs().seg;
 233
 234#ifdef CONFIG_FPU
 235        if (!FPU_IS_EMU) {
 236                /* Copy the current fpu state */
 237                asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
 238
 239                if (p->thread.fpstate[0])
 240                  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
 241                                "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
 242                                : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
 243                                : "memory");
 244                /* Restore the state in case the fpu was busy */
 245                asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
 246        }
 247#endif
 248
 249        return 0;
 250}
 251
 252/* Fill in the fpu structure for a core dump.  */
 253
 254int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 255{
 256#ifdef CONFIG_FPU
 257        char fpustate[216];
 258
 259        if (FPU_IS_EMU) {
 260                int i;
 261
 262                memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
 263                memcpy(fpu->fpregs, current->thread.fp, 96);
 264                /* Convert internal fpu reg representation
 265                 * into long double format
 266                 */
 267                for (i = 0; i < 24; i += 3)
 268                        fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
 269                                         ((fpu->fpregs[i] & 0x0000ffff) << 16);
 270                return 1;
 271        }
 272
 273        /* First dump the fpu context to avoid protocol violation.  */
 274        asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
 275        if (!fpustate[0])
 276                return 0;
 277
 278        asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
 279                :: "m" (fpu->fpcntl[0])
 280                : "memory");
 281        asm volatile ("fmovemx %/fp0-%/fp7,%0"
 282                :: "m" (fpu->fpregs[0])
 283                : "memory");
 284#endif
 285        return 1;
 286}
 287
 288/*
 289 *      Generic dumping code. Used for panic and debug.
 290 */
 291void dump(struct pt_regs *fp)
 292{
 293        unsigned long   *sp;
 294        unsigned char   *tp;
 295        int             i;
 296
 297        printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
 298        printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
 299
 300        if (current->mm) {
 301                printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
 302                        (int) current->mm->start_code,
 303                        (int) current->mm->end_code,
 304                        (int) current->mm->start_data,
 305                        (int) current->mm->end_data,
 306                        (int) current->mm->end_data,
 307                        (int) current->mm->brk);
 308                printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
 309                        (int) current->mm->start_stack,
 310                        (int)(((unsigned long) current) + THREAD_SIZE));
 311        }
 312
 313        printk(KERN_EMERG "PC: %08lx\n", fp->pc);
 314        printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
 315        printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 316                fp->d0, fp->d1, fp->d2, fp->d3);
 317        printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
 318                fp->d4, fp->d5, fp->a0, fp->a1);
 319        printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %p\n",
 320                (unsigned int) rdusp(), fp);
 321
 322        printk(KERN_EMERG "\nCODE:");
 323        tp = ((unsigned char *) fp->pc) - 0x20;
 324        for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
 325                if ((i % 0x10) == 0)
 326                        printk(KERN_EMERG "%p: ", tp + i);
 327                printk("%08x ", (int) *sp++);
 328        }
 329        printk(KERN_EMERG "\n");
 330
 331        printk(KERN_EMERG "KERNEL STACK:");
 332        tp = ((unsigned char *) fp) - 0x40;
 333        for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
 334                if ((i % 0x10) == 0)
 335                        printk(KERN_EMERG "%p: ", tp + i);
 336                printk("%08x ", (int) *sp++);
 337        }
 338        printk(KERN_EMERG "\n");
 339
 340        printk(KERN_EMERG "USER STACK:");
 341        tp = (unsigned char *) (rdusp() - 0x10);
 342        for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
 343                if ((i % 0x10) == 0)
 344                        printk(KERN_EMERG "%p: ", tp + i);
 345                printk("%08x ", (int) *sp++);
 346        }
 347        printk(KERN_EMERG "\n");
 348}
 349
 350/*
 351 * sys_execve() executes a new program.
 352 */
 353asmlinkage int sys_execve(const char *name,
 354                          const char *const *argv,
 355                          const char *const *envp)
 356{
 357        int error;
 358        char * filename;
 359        struct pt_regs *regs = (struct pt_regs *) &name;
 360
 361        filename = getname(name);
 362        error = PTR_ERR(filename);
 363        if (IS_ERR(filename))
 364                return error;
 365        error = do_execve(filename, argv, envp, regs);
 366        putname(filename);
 367        return error;
 368}
 369
 370unsigned long get_wchan(struct task_struct *p)
 371{
 372        unsigned long fp, pc;
 373        unsigned long stack_page;
 374        int count = 0;
 375        if (!p || p == current || p->state == TASK_RUNNING)
 376                return 0;
 377
 378        stack_page = (unsigned long)p;
 379        fp = ((struct switch_stack *)p->thread.ksp)->a6;
 380        do {
 381                if (fp < stack_page+sizeof(struct thread_info) ||
 382                    fp >= THREAD_SIZE-8+stack_page)
 383                        return 0;
 384                pc = ((unsigned long *)fp)[1];
 385                if (!in_sched_functions(pc))
 386                        return pc;
 387                fp = *(unsigned long *) fp;
 388        } while (count++ < 16);
 389        return 0;
 390}
 391
 392/*
 393 * Return saved PC of a blocked thread.
 394 */
 395unsigned long thread_saved_pc(struct task_struct *tsk)
 396{
 397        struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
 398
 399        /* Check whether the thread is blocked in resume() */
 400        if (in_sched_functions(sw->retpc))
 401                return ((unsigned long *)sw->a6)[1];
 402        else
 403                return sw->retpc;
 404}
 405
 406