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}
 338
 339/*
 340 * Free current thread data structures etc..
 341 */
 342void exit_thread(void)
 343{
 344        /*
 345         * See arch/sparc/kernel/process.c for the precedent for doing
 346         * this -- RPC.
 347         *
 348         * The SH-5 FPU save/restore approach relies on
 349         * last_task_used_math pointing to a live task_struct.  When
 350         * another task tries to use the FPU for the 1st time, the FPUDIS
 351         * trap handling (see arch/sh/kernel/cpu/sh5/fpu.c) will save the
 352         * existing FPU state to the FP regs field within
 353         * last_task_used_math before re-loading the new task's FPU state
 354         * (or initialising it if the FPU has been used before).  So if
 355         * last_task_used_math is stale, and its page has already been
 356         * re-allocated for another use, the consequences are rather
 357         * grim. Unless we null it here, there is no other path through
 358         * which it would get safely nulled.
 359         */
 360#ifdef CONFIG_SH_FPU
 361        if (last_task_used_math == current) {
 362                last_task_used_math = NULL;
 363        }
 364#endif
 365}
 366
 367void flush_thread(void)
 368{
 369
 370        /* Called by fs/exec.c (flush_old_exec) to remove traces of a
 371         * previously running executable. */
 372#ifdef CONFIG_SH_FPU
 373        if (last_task_used_math == current) {
 374                last_task_used_math = NULL;
 375        }
 376        /* Force FPU state to be reinitialised after exec */
 377        clear_used_math();
 378#endif
 379
 380        /* if we are a kernel thread, about to change to user thread,
 381         * update kreg
 382         */
 383        if(current->thread.kregs==&fake_swapper_regs) {
 384          current->thread.kregs =
 385             ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
 386          current->thread.uregs = current->thread.kregs;
 387        }
 388}
 389
 390void release_thread(struct task_struct *dead_task)
 391{
 392        /* do nothing */
 393}
 394
 395/* Fill in the fpu structure for a core dump.. */
 396int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 397{
 398#ifdef CONFIG_SH_FPU
 399        int fpvalid;
 400        struct task_struct *tsk = current;
 401
 402        fpvalid = !!tsk_used_math(tsk);
 403        if (fpvalid) {
 404                if (current == last_task_used_math) {
 405                        enable_fpu();
 406                        save_fpu(tsk, regs);
 407                        disable_fpu();
 408                        last_task_used_math = 0;
 409                        regs->sr |= SR_FD;
 410                }
 411
 412                memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
 413        }
 414
 415        return fpvalid;
 416#else
 417        return 0; /* Task didn't use the fpu at all. */
 418#endif
 419}
 420
 421asmlinkage void ret_from_fork(void);
 422
 423int copy_thread(unsigned long clone_flags, unsigned long usp,
 424                unsigned long unused,
 425                struct task_struct *p, struct pt_regs *regs)
 426{
 427        struct pt_regs *childregs;
 428
 429#ifdef CONFIG_SH_FPU
 430        if(last_task_used_math == current) {
 431                enable_fpu();
 432                save_fpu(current, regs);
 433                disable_fpu();
 434                last_task_used_math = NULL;
 435                regs->sr |= SR_FD;
 436        }
 437#endif
 438        /* Copy from sh version */
 439        childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
 440
 441        *childregs = *regs;
 442
 443        /*
 444         * Sign extend the edited stack.
 445         * Note that thread.pc and thread.pc will stay
 446         * 32-bit wide and context switch must take care
 447         * of NEFF sign extension.
 448         */
 449        if (user_mode(regs)) {
 450                childregs->regs[15] = neff_sign_extend(usp);
 451                p->thread.uregs = childregs;
 452        } else {
 453                childregs->regs[15] =
 454                        neff_sign_extend((unsigned long)task_stack_page(p) +
 455                                         THREAD_SIZE);
 456        }
 457
 458        childregs->regs[9] = 0; /* Set return value for child */
 459        childregs->sr |= SR_FD; /* Invalidate FPU flag */
 460
 461        p->thread.sp = (unsigned long) childregs;
 462        p->thread.pc = (unsigned long) ret_from_fork;
 463
 464        return 0;
 465}
 466
 467asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
 468                        unsigned long r4, unsigned long r5,
 469                        unsigned long r6, unsigned long r7,
 470                        struct pt_regs *pregs)
 471{
 472        return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
 473}
 474
 475asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
 476                         unsigned long r4, unsigned long r5,
 477                         unsigned long r6, unsigned long r7,
 478                         struct pt_regs *pregs)
 479{
 480        if (!newsp)
 481                newsp = pregs->regs[15];
 482        return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
 483}
 484
 485/*
 486 * This is trivial, and on the face of it looks like it
 487 * could equally well be done in user mode.
 488 *
 489 * Not so, for quite unobvious reasons - register pressure.
 490 * In user mode vfork() cannot have a stack frame, and if
 491 * done by calling the "clone()" system call directly, you
 492 * do not have enough call-clobbered registers to hold all
 493 * the information you need.
 494 */
 495asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
 496                         unsigned long r4, unsigned long r5,
 497                         unsigned long r6, unsigned long r7,
 498                         struct pt_regs *pregs)
 499{
 500        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
 501}
 502
 503/*
 504 * sys_execve() executes a new program.
 505 */
 506asmlinkage int sys_execve(char *ufilename, char **uargv,
 507                          char **uenvp, unsigned long r5,
 508                          unsigned long r6, unsigned long r7,
 509                          struct pt_regs *pregs)
 510{
 511        int error;
 512        char *filename;
 513
 514        filename = getname((char __user *)ufilename);
 515        error = PTR_ERR(filename);
 516        if (IS_ERR(filename))
 517                goto out;
 518
 519        error = do_execve(filename,
 520                          (char __user * __user *)uargv,
 521                          (char __user * __user *)uenvp,
 522                          pregs);
 523        putname(filename);
 524out:
 525        return error;
 526}
 527
 528/*
 529 * These bracket the sleeping functions..
 530 */
 531extern void interruptible_sleep_on(wait_queue_head_t *q);
 532
 533#define mid_sched       ((unsigned long) interruptible_sleep_on)
 534
 535#ifdef CONFIG_FRAME_POINTER
 536static int in_sh64_switch_to(unsigned long pc)
 537{
 538        extern char __sh64_switch_to_end;
 539        /* For a sleeping task, the PC is somewhere in the middle of the function,
 540           so we don't have to worry about masking the LSB off */
 541        return (pc >= (unsigned long) sh64_switch_to) &&
 542               (pc < (unsigned long) &__sh64_switch_to_end);
 543}
 544#endif
 545
 546unsigned long get_wchan(struct task_struct *p)
 547{
 548        unsigned long pc;
 549
 550        if (!p || p == current || p->state == TASK_RUNNING)
 551                return 0;
 552
 553        /*
 554         * The same comment as on the Alpha applies here, too ...
 555         */
 556        pc = thread_saved_pc(p);
 557
 558#ifdef CONFIG_FRAME_POINTER
 559        if (in_sh64_switch_to(pc)) {
 560                unsigned long schedule_fp;
 561                unsigned long sh64_switch_to_fp;
 562                unsigned long schedule_caller_pc;
 563
 564                sh64_switch_to_fp = (long) p->thread.sp;
 565                /* r14 is saved at offset 4 in the sh64_switch_to frame */
 566                schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
 567
 568                /* and the caller of 'schedule' is (currently!) saved at offset 24
 569                   in the frame of schedule (from disasm) */
 570                schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
 571                return schedule_caller_pc;
 572        }
 573#endif
 574        return pc;
 575}
 576