linux/arch/sh/kernel/process_64.c
<<
>>
Prefs
   1/*
   2 * arch/sh/kernel/process_64.c
   3 *
   4 * This file handles the architecture-dependent parts of process handling..
   5 *
   6 * Copyright (C) 2000, 2001  Paolo Alberelli
   7 * Copyright (C) 2003 - 2007  Paul Mundt
   8 * Copyright (C) 2003, 2004 Richard Curnow
   9 *
  10 * Started from SH3/4 version:
  11 *   Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  12 *
  13 *   In turn started from i386 version:
  14 *     Copyright (C) 1995  Linus Torvalds
  15 *
  16 * This file is subject to the terms and conditions of the GNU General Public
  17 * License.  See the file "COPYING" in the main directory of this archive
  18 * for more details.
  19 */
  20#include <linux/mm.h>
  21#include <linux/fs.h>
  22#include <linux/ptrace.h>
  23#include <linux/reboot.h>
  24#include <linux/init.h>
  25#include <linux/module.h>
  26#include <linux/io.h>
  27#include <asm/syscalls.h>
  28#include <asm/uaccess.h>
  29#include <asm/pgtable.h>
  30#include <asm/mmu_context.h>
  31#include <asm/fpu.h>
  32
  33struct task_struct *last_task_used_math = NULL;
  34
  35void machine_restart(char * __unused)
  36{
  37        extern void phys_stext(void);
  38
  39        phys_stext();
  40}
  41
  42void machine_halt(void)
  43{
  44        for (;;);
  45}
  46
  47void machine_power_off(void)
  48{
  49        __asm__ __volatile__ (
  50                "sleep\n\t"
  51                "synci\n\t"
  52                "nop;nop;nop;nop\n\t"
  53        );
  54
  55        panic("Unexpected wakeup!\n");
  56}
  57
  58void show_regs(struct pt_regs * regs)
  59{
  60        unsigned long long ah, al, bh, bl, ch, cl;
  61
  62        printk("\n");
  63
  64        ah = (regs->pc) >> 32;
  65        al = (regs->pc) & 0xffffffff;
  66        bh = (regs->regs[18]) >> 32;
  67        bl = (regs->regs[18]) & 0xffffffff;
  68        ch = (regs->regs[15]) >> 32;
  69        cl = (regs->regs[15]) & 0xffffffff;
  70        printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
  71               ah, al, bh, bl, ch, cl);
  72
  73        ah = (regs->sr) >> 32;
  74        al = (regs->sr) & 0xffffffff;
  75        asm volatile ("getcon   " __TEA ", %0" : "=r" (bh));
  76        asm volatile ("getcon   " __TEA ", %0" : "=r" (bl));
  77        bh = (bh) >> 32;
  78        bl = (bl) & 0xffffffff;
  79        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (ch));
  80        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (cl));
  81        ch = (ch) >> 32;
  82        cl = (cl) & 0xffffffff;
  83        printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
  84               ah, al, bh, bl, ch, cl);
  85
  86        ah = (regs->regs[0]) >> 32;
  87        al = (regs->regs[0]) & 0xffffffff;
  88        bh = (regs->regs[1]) >> 32;
  89        bl = (regs->regs[1]) & 0xffffffff;
  90        ch = (regs->regs[2]) >> 32;
  91        cl = (regs->regs[2]) & 0xffffffff;
  92        printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
  93               ah, al, bh, bl, ch, cl);
  94
  95        ah = (regs->regs[3]) >> 32;
  96        al = (regs->regs[3]) & 0xffffffff;
  97        bh = (regs->regs[4]) >> 32;
  98        bl = (regs->regs[4]) & 0xffffffff;
  99        ch = (regs->regs[5]) >> 32;
 100        cl = (regs->regs[5]) & 0xffffffff;
 101        printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
 102               ah, al, bh, bl, ch, cl);
 103
 104        ah = (regs->regs[6]) >> 32;
 105        al = (regs->regs[6]) & 0xffffffff;
 106        bh = (regs->regs[7]) >> 32;
 107        bl = (regs->regs[7]) & 0xffffffff;
 108        ch = (regs->regs[8]) >> 32;
 109        cl = (regs->regs[8]) & 0xffffffff;
 110        printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
 111               ah, al, bh, bl, ch, cl);
 112
 113        ah = (regs->regs[9]) >> 32;
 114        al = (regs->regs[9]) & 0xffffffff;
 115        bh = (regs->regs[10]) >> 32;
 116        bl = (regs->regs[10]) & 0xffffffff;
 117        ch = (regs->regs[11]) >> 32;
 118        cl = (regs->regs[11]) & 0xffffffff;
 119        printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
 120               ah, al, bh, bl, ch, cl);
 121
 122        ah = (regs->regs[12]) >> 32;
 123        al = (regs->regs[12]) & 0xffffffff;
 124        bh = (regs->regs[13]) >> 32;
 125        bl = (regs->regs[13]) & 0xffffffff;
 126        ch = (regs->regs[14]) >> 32;
 127        cl = (regs->regs[14]) & 0xffffffff;
 128        printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
 129               ah, al, bh, bl, ch, cl);
 130
 131        ah = (regs->regs[16]) >> 32;
 132        al = (regs->regs[16]) & 0xffffffff;
 133        bh = (regs->regs[17]) >> 32;
 134        bl = (regs->regs[17]) & 0xffffffff;
 135        ch = (regs->regs[19]) >> 32;
 136        cl = (regs->regs[19]) & 0xffffffff;
 137        printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
 138               ah, al, bh, bl, ch, cl);
 139
 140        ah = (regs->regs[20]) >> 32;
 141        al = (regs->regs[20]) & 0xffffffff;
 142        bh = (regs->regs[21]) >> 32;
 143        bl = (regs->regs[21]) & 0xffffffff;
 144        ch = (regs->regs[22]) >> 32;
 145        cl = (regs->regs[22]) & 0xffffffff;
 146        printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
 147               ah, al, bh, bl, ch, cl);
 148
 149        ah = (regs->regs[23]) >> 32;
 150        al = (regs->regs[23]) & 0xffffffff;
 151        bh = (regs->regs[24]) >> 32;
 152        bl = (regs->regs[24]) & 0xffffffff;
 153        ch = (regs->regs[25]) >> 32;
 154        cl = (regs->regs[25]) & 0xffffffff;
 155        printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
 156               ah, al, bh, bl, ch, cl);
 157
 158        ah = (regs->regs[26]) >> 32;
 159        al = (regs->regs[26]) & 0xffffffff;
 160        bh = (regs->regs[27]) >> 32;
 161        bl = (regs->regs[27]) & 0xffffffff;
 162        ch = (regs->regs[28]) >> 32;
 163        cl = (regs->regs[28]) & 0xffffffff;
 164        printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
 165               ah, al, bh, bl, ch, cl);
 166
 167        ah = (regs->regs[29]) >> 32;
 168        al = (regs->regs[29]) & 0xffffffff;
 169        bh = (regs->regs[30]) >> 32;
 170        bl = (regs->regs[30]) & 0xffffffff;
 171        ch = (regs->regs[31]) >> 32;
 172        cl = (regs->regs[31]) & 0xffffffff;
 173        printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
 174               ah, al, bh, bl, ch, cl);
 175
 176        ah = (regs->regs[32]) >> 32;
 177        al = (regs->regs[32]) & 0xffffffff;
 178        bh = (regs->regs[33]) >> 32;
 179        bl = (regs->regs[33]) & 0xffffffff;
 180        ch = (regs->regs[34]) >> 32;
 181        cl = (regs->regs[34]) & 0xffffffff;
 182        printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
 183               ah, al, bh, bl, ch, cl);
 184
 185        ah = (regs->regs[35]) >> 32;
 186        al = (regs->regs[35]) & 0xffffffff;
 187        bh = (regs->regs[36]) >> 32;
 188        bl = (regs->regs[36]) & 0xffffffff;
 189        ch = (regs->regs[37]) >> 32;
 190        cl = (regs->regs[37]) & 0xffffffff;
 191        printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
 192               ah, al, bh, bl, ch, cl);
 193
 194        ah = (regs->regs[38]) >> 32;
 195        al = (regs->regs[38]) & 0xffffffff;
 196        bh = (regs->regs[39]) >> 32;
 197        bl = (regs->regs[39]) & 0xffffffff;
 198        ch = (regs->regs[40]) >> 32;
 199        cl = (regs->regs[40]) & 0xffffffff;
 200        printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
 201               ah, al, bh, bl, ch, cl);
 202
 203        ah = (regs->regs[41]) >> 32;
 204        al = (regs->regs[41]) & 0xffffffff;
 205        bh = (regs->regs[42]) >> 32;
 206        bl = (regs->regs[42]) & 0xffffffff;
 207        ch = (regs->regs[43]) >> 32;
 208        cl = (regs->regs[43]) & 0xffffffff;
 209        printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
 210               ah, al, bh, bl, ch, cl);
 211
 212        ah = (regs->regs[44]) >> 32;
 213        al = (regs->regs[44]) & 0xffffffff;
 214        bh = (regs->regs[45]) >> 32;
 215        bl = (regs->regs[45]) & 0xffffffff;
 216        ch = (regs->regs[46]) >> 32;
 217        cl = (regs->regs[46]) & 0xffffffff;
 218        printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
 219               ah, al, bh, bl, ch, cl);
 220
 221        ah = (regs->regs[47]) >> 32;
 222        al = (regs->regs[47]) & 0xffffffff;
 223        bh = (regs->regs[48]) >> 32;
 224        bl = (regs->regs[48]) & 0xffffffff;
 225        ch = (regs->regs[49]) >> 32;
 226        cl = (regs->regs[49]) & 0xffffffff;
 227        printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
 228               ah, al, bh, bl, ch, cl);
 229
 230        ah = (regs->regs[50]) >> 32;
 231        al = (regs->regs[50]) & 0xffffffff;
 232        bh = (regs->regs[51]) >> 32;
 233        bl = (regs->regs[51]) & 0xffffffff;
 234        ch = (regs->regs[52]) >> 32;
 235        cl = (regs->regs[52]) & 0xffffffff;
 236        printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
 237               ah, al, bh, bl, ch, cl);
 238
 239        ah = (regs->regs[53]) >> 32;
 240        al = (regs->regs[53]) & 0xffffffff;
 241        bh = (regs->regs[54]) >> 32;
 242        bl = (regs->regs[54]) & 0xffffffff;
 243        ch = (regs->regs[55]) >> 32;
 244        cl = (regs->regs[55]) & 0xffffffff;
 245        printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
 246               ah, al, bh, bl, ch, cl);
 247
 248        ah = (regs->regs[56]) >> 32;
 249        al = (regs->regs[56]) & 0xffffffff;
 250        bh = (regs->regs[57]) >> 32;
 251        bl = (regs->regs[57]) & 0xffffffff;
 252        ch = (regs->regs[58]) >> 32;
 253        cl = (regs->regs[58]) & 0xffffffff;
 254        printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
 255               ah, al, bh, bl, ch, cl);
 256
 257        ah = (regs->regs[59]) >> 32;
 258        al = (regs->regs[59]) & 0xffffffff;
 259        bh = (regs->regs[60]) >> 32;
 260        bl = (regs->regs[60]) & 0xffffffff;
 261        ch = (regs->regs[61]) >> 32;
 262        cl = (regs->regs[61]) & 0xffffffff;
 263        printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
 264               ah, al, bh, bl, ch, cl);
 265
 266        ah = (regs->regs[62]) >> 32;
 267        al = (regs->regs[62]) & 0xffffffff;
 268        bh = (regs->tregs[0]) >> 32;
 269        bl = (regs->tregs[0]) & 0xffffffff;
 270        ch = (regs->tregs[1]) >> 32;
 271        cl = (regs->tregs[1]) & 0xffffffff;
 272        printk("R62 : %08Lx%08Lx T0  : %08Lx%08Lx T1  : %08Lx%08Lx\n",
 273               ah, al, bh, bl, ch, cl);
 274
 275        ah = (regs->tregs[2]) >> 32;
 276        al = (regs->tregs[2]) & 0xffffffff;
 277        bh = (regs->tregs[3]) >> 32;
 278        bl = (regs->tregs[3]) & 0xffffffff;
 279        ch = (regs->tregs[4]) >> 32;
 280        cl = (regs->tregs[4]) & 0xffffffff;
 281        printk("T2  : %08Lx%08Lx T3  : %08Lx%08Lx T4  : %08Lx%08Lx\n",
 282               ah, al, bh, bl, ch, cl);
 283
 284        ah = (regs->tregs[5]) >> 32;
 285        al = (regs->tregs[5]) & 0xffffffff;
 286        bh = (regs->tregs[6]) >> 32;
 287        bl = (regs->tregs[6]) & 0xffffffff;
 288        ch = (regs->tregs[7]) >> 32;
 289        cl = (regs->tregs[7]) & 0xffffffff;
 290        printk("T5  : %08Lx%08Lx T6  : %08Lx%08Lx T7  : %08Lx%08Lx\n",
 291               ah, al, bh, bl, ch, cl);
 292
 293        /*
 294         * If we're in kernel mode, dump the stack too..
 295         */
 296        if (!user_mode(regs)) {
 297                void show_stack(struct task_struct *tsk, unsigned long *sp);
 298                unsigned long sp = regs->regs[15] & 0xffffffff;
 299                struct task_struct *tsk = get_current();
 300
 301                tsk->thread.kregs = regs;
 302
 303                show_stack(tsk, (unsigned long *)sp);
 304        }
 305}
 306
 307/*
 308 * Create a kernel thread
 309 */
 310ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
 311{
 312        do_exit(fn(arg));
 313}
 314
 315/*
 316 * This is the mechanism for creating a new kernel thread.
 317 *
 318 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
 319 * who haven't done an "execve()") should use this: it will work within
 320 * a system call from a "real" process, but the process memory space will
 321 * not be freed until both the parent and the child have exited.
 322 */
 323int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 324{
 325        struct pt_regs regs;
 326
 327        memset(&regs, 0, sizeof(regs));
 328        regs.regs[2] = (unsigned long)arg;
 329        regs.regs[3] = (unsigned long)fn;
 330
 331        regs.pc = (unsigned long)kernel_thread_helper;
 332        regs.sr = (1 << 30);
 333
 334        /* Ok, create the new process.. */
 335        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
 336                      &regs, 0, NULL, NULL);
 337}
 338EXPORT_SYMBOL(kernel_thread);
 339
 340/*
 341 * Free current thread data structures etc..
 342 */
 343void exit_thread(void)
 344{
 345        /*
 346         * See arch/sparc/kernel/process.c for the precedent for doing
 347         * this -- RPC.
 348         *
 349         * The SH-5 FPU save/restore approach relies on
 350         * last_task_used_math pointing to a live task_struct.  When
 351         * another task tries to use the FPU for the 1st time, the FPUDIS
 352         * trap handling (see arch/sh/kernel/cpu/sh5/fpu.c) will save the
 353         * existing FPU state to the FP regs field within
 354         * last_task_used_math before re-loading the new task's FPU state
 355         * (or initialising it if the FPU has been used before).  So if
 356         * last_task_used_math is stale, and its page has already been
 357         * re-allocated for another use, the consequences are rather
 358         * grim. Unless we null it here, there is no other path through
 359         * which it would get safely nulled.
 360         */
 361#ifdef CONFIG_SH_FPU
 362        if (last_task_used_math == current) {
 363                last_task_used_math = NULL;
 364        }
 365#endif
 366}
 367
 368void flush_thread(void)
 369{
 370
 371        /* Called by fs/exec.c (setup_new_exec) to remove traces of a
 372         * previously running executable. */
 373#ifdef CONFIG_SH_FPU
 374        if (last_task_used_math == current) {
 375                last_task_used_math = NULL;
 376        }
 377        /* Force FPU state to be reinitialised after exec */
 378        clear_used_math();
 379#endif
 380
 381        /* if we are a kernel thread, about to change to user thread,
 382         * update kreg
 383         */
 384        if(current->thread.kregs==&fake_swapper_regs) {
 385          current->thread.kregs =
 386             ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
 387          current->thread.uregs = current->thread.kregs;
 388        }
 389}
 390
 391void release_thread(struct task_struct *dead_task)
 392{
 393        /* do nothing */
 394}
 395
 396/* Fill in the fpu structure for a core dump.. */
 397int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 398{
 399#ifdef CONFIG_SH_FPU
 400        int fpvalid;
 401        struct task_struct *tsk = current;
 402
 403        fpvalid = !!tsk_used_math(tsk);
 404        if (fpvalid) {
 405                if (current == last_task_used_math) {
 406                        enable_fpu();
 407                        save_fpu(tsk);
 408                        disable_fpu();
 409                        last_task_used_math = 0;
 410                        regs->sr |= SR_FD;
 411                }
 412
 413                memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
 414        }
 415
 416        return fpvalid;
 417#else
 418        return 0; /* Task didn't use the fpu at all. */
 419#endif
 420}
 421EXPORT_SYMBOL(dump_fpu);
 422
 423asmlinkage void ret_from_fork(void);
 424
 425int copy_thread(unsigned long clone_flags, unsigned long usp,
 426                unsigned long unused,
 427                struct task_struct *p, struct pt_regs *regs)
 428{
 429        struct pt_regs *childregs;
 430
 431#ifdef CONFIG_SH_FPU
 432        if(last_task_used_math == current) {
 433                enable_fpu();
 434                save_fpu(current);
 435                disable_fpu();
 436                last_task_used_math = NULL;
 437                regs->sr |= SR_FD;
 438        }
 439#endif
 440        /* Copy from sh version */
 441        childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
 442
 443        *childregs = *regs;
 444
 445        /*
 446         * Sign extend the edited stack.
 447         * Note that thread.pc and thread.pc will stay
 448         * 32-bit wide and context switch must take care
 449         * of NEFF sign extension.
 450         */
 451        if (user_mode(regs)) {
 452                childregs->regs[15] = neff_sign_extend(usp);
 453                p->thread.uregs = childregs;
 454        } else {
 455                childregs->regs[15] =
 456                        neff_sign_extend((unsigned long)task_stack_page(p) +
 457                                         THREAD_SIZE);
 458        }
 459
 460        childregs->regs[9] = 0; /* Set return value for child */
 461        childregs->sr |= SR_FD; /* Invalidate FPU flag */
 462
 463        p->thread.sp = (unsigned long) childregs;
 464        p->thread.pc = (unsigned long) ret_from_fork;
 465
 466        return 0;
 467}
 468
 469asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
 470                        unsigned long r4, unsigned long r5,
 471                        unsigned long r6, unsigned long r7,
 472                        struct pt_regs *pregs)
 473{
 474        return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
 475}
 476
 477asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
 478                         unsigned long r4, unsigned long r5,
 479                         unsigned long r6, unsigned long r7,
 480                         struct pt_regs *pregs)
 481{
 482        if (!newsp)
 483                newsp = pregs->regs[15];
 484        return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
 485}
 486
 487/*
 488 * This is trivial, and on the face of it looks like it
 489 * could equally well be done in user mode.
 490 *
 491 * Not so, for quite unobvious reasons - register pressure.
 492 * In user mode vfork() cannot have a stack frame, and if
 493 * done by calling the "clone()" system call directly, you
 494 * do not have enough call-clobbered registers to hold all
 495 * the information you need.
 496 */
 497asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
 498                         unsigned long r4, unsigned long r5,
 499                         unsigned long r6, unsigned long r7,
 500                         struct pt_regs *pregs)
 501{
 502        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
 503}
 504
 505/*
 506 * sys_execve() executes a new program.
 507 */
 508asmlinkage int sys_execve(char *ufilename, char **uargv,
 509                          char **uenvp, unsigned long r5,
 510                          unsigned long r6, unsigned long r7,
 511                          struct pt_regs *pregs)
 512{
 513        int error;
 514        char *filename;
 515
 516        filename = getname((char __user *)ufilename);
 517        error = PTR_ERR(filename);
 518        if (IS_ERR(filename))
 519                goto out;
 520
 521        error = do_execve(filename,
 522                          (char __user * __user *)uargv,
 523                          (char __user * __user *)uenvp,
 524                          pregs);
 525        putname(filename);
 526out:
 527        return error;
 528}
 529
 530/*
 531 * These bracket the sleeping functions..
 532 */
 533extern void interruptible_sleep_on(wait_queue_head_t *q);
 534
 535#define mid_sched       ((unsigned long) interruptible_sleep_on)
 536
 537#ifdef CONFIG_FRAME_POINTER
 538static int in_sh64_switch_to(unsigned long pc)
 539{
 540        extern char __sh64_switch_to_end;
 541        /* For a sleeping task, the PC is somewhere in the middle of the function,
 542           so we don't have to worry about masking the LSB off */
 543        return (pc >= (unsigned long) sh64_switch_to) &&
 544               (pc < (unsigned long) &__sh64_switch_to_end);
 545}
 546#endif
 547
 548unsigned long get_wchan(struct task_struct *p)
 549{
 550        unsigned long pc;
 551
 552        if (!p || p == current || p->state == TASK_RUNNING)
 553                return 0;
 554
 555        /*
 556         * The same comment as on the Alpha applies here, too ...
 557         */
 558        pc = thread_saved_pc(p);
 559
 560#ifdef CONFIG_FRAME_POINTER
 561        if (in_sh64_switch_to(pc)) {
 562                unsigned long schedule_fp;
 563                unsigned long sh64_switch_to_fp;
 564                unsigned long schedule_caller_pc;
 565
 566                sh64_switch_to_fp = (long) p->thread.sp;
 567                /* r14 is saved at offset 4 in the sh64_switch_to frame */
 568                schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
 569
 570                /* and the caller of 'schedule' is (currently!) saved at offset 24
 571                   in the frame of schedule (from disasm) */
 572                schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
 573                return schedule_caller_pc;
 574        }
 575#endif
 576        return pc;
 577}
 578
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.