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