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