linux/arch/sparc64/kernel/process.c
<<
>>
Prefs
   1/*  arch/sparc64/kernel/process.c
   2 *
   3 *  Copyright (C) 1995, 1996, 2008 David S. Miller (davem@davemloft.net)
   4 *  Copyright (C) 1996       Eddie C. Dost   (ecd@skynet.be)
   5 *  Copyright (C) 1997, 1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
   6 */
   7
   8/*
   9 * This file handles the architecture-dependent parts of process handling..
  10 */
  11
  12#include <stdarg.h>
  13
  14#include <linux/errno.h>
  15#include <linux/module.h>
  16#include <linux/sched.h>
  17#include <linux/kernel.h>
  18#include <linux/mm.h>
  19#include <linux/fs.h>
  20#include <linux/smp.h>
  21#include <linux/stddef.h>
  22#include <linux/ptrace.h>
  23#include <linux/slab.h>
  24#include <linux/user.h>
  25#include <linux/reboot.h>
  26#include <linux/delay.h>
  27#include <linux/compat.h>
  28#include <linux/tick.h>
  29#include <linux/init.h>
  30#include <linux/cpu.h>
  31#include <linux/elfcore.h>
  32#include <linux/sysrq.h>
  33
  34#include <asm/oplib.h>
  35#include <asm/uaccess.h>
  36#include <asm/system.h>
  37#include <asm/page.h>
  38#include <asm/pgalloc.h>
  39#include <asm/pgtable.h>
  40#include <asm/processor.h>
  41#include <asm/pstate.h>
  42#include <asm/elf.h>
  43#include <asm/fpumacro.h>
  44#include <asm/head.h>
  45#include <asm/cpudata.h>
  46#include <asm/mmu_context.h>
  47#include <asm/unistd.h>
  48#include <asm/hypervisor.h>
  49#include <asm/sstate.h>
  50#include <asm/reboot.h>
  51#include <asm/syscalls.h>
  52#include <asm/irq_regs.h>
  53#include <asm/smp.h>
  54
  55#include "kstack.h"
  56
  57static void sparc64_yield(int cpu)
  58{
  59        if (tlb_type != hypervisor)
  60                return;
  61
  62        clear_thread_flag(TIF_POLLING_NRFLAG);
  63        smp_mb__after_clear_bit();
  64
  65        while (!need_resched() && !cpu_is_offline(cpu)) {
  66                unsigned long pstate;
  67
  68                /* Disable interrupts. */
  69                __asm__ __volatile__(
  70                        "rdpr %%pstate, %0\n\t"
  71                        "andn %0, %1, %0\n\t"
  72                        "wrpr %0, %%g0, %%pstate"
  73                        : "=&r" (pstate)
  74                        : "i" (PSTATE_IE));
  75
  76                if (!need_resched() && !cpu_is_offline(cpu))
  77                        sun4v_cpu_yield();
  78
  79                /* Re-enable interrupts. */
  80                __asm__ __volatile__(
  81                        "rdpr %%pstate, %0\n\t"
  82                        "or %0, %1, %0\n\t"
  83                        "wrpr %0, %%g0, %%pstate"
  84                        : "=&r" (pstate)
  85                        : "i" (PSTATE_IE));
  86        }
  87
  88        set_thread_flag(TIF_POLLING_NRFLAG);
  89}
  90
  91/* The idle loop on sparc64. */
  92void cpu_idle(void)
  93{
  94        int cpu = smp_processor_id();
  95
  96        set_thread_flag(TIF_POLLING_NRFLAG);
  97
  98        while(1) {
  99                tick_nohz_stop_sched_tick(1);
 100
 101                while (!need_resched() && !cpu_is_offline(cpu))
 102                        sparc64_yield(cpu);
 103
 104                tick_nohz_restart_sched_tick();
 105
 106                preempt_enable_no_resched();
 107
 108#ifdef CONFIG_HOTPLUG_CPU
 109                if (cpu_is_offline(cpu))
 110                        cpu_play_dead();
 111#endif
 112
 113                schedule();
 114                preempt_disable();
 115        }
 116}
 117
 118void machine_halt(void)
 119{
 120        sstate_halt();
 121        prom_halt();
 122        panic("Halt failed!");
 123}
 124
 125void machine_alt_power_off(void)
 126{
 127        sstate_poweroff();
 128        prom_halt_power_off();
 129        panic("Power-off failed!");
 130}
 131
 132void machine_restart(char * cmd)
 133{
 134        char *p;
 135        
 136        sstate_reboot();
 137        p = strchr (reboot_command, '\n');
 138        if (p) *p = 0;
 139        if (cmd)
 140                prom_reboot(cmd);
 141        if (*reboot_command)
 142                prom_reboot(reboot_command);
 143        prom_reboot("");
 144        panic("Reboot failed!");
 145}
 146
 147#ifdef CONFIG_COMPAT
 148static void show_regwindow32(struct pt_regs *regs)
 149{
 150        struct reg_window32 __user *rw;
 151        struct reg_window32 r_w;
 152        mm_segment_t old_fs;
 153        
 154        __asm__ __volatile__ ("flushw");
 155        rw = compat_ptr((unsigned)regs->u_regs[14]);
 156        old_fs = get_fs();
 157        set_fs (USER_DS);
 158        if (copy_from_user (&r_w, rw, sizeof(r_w))) {
 159                set_fs (old_fs);
 160                return;
 161        }
 162
 163        set_fs (old_fs);                        
 164        printk("l0: %08x l1: %08x l2: %08x l3: %08x "
 165               "l4: %08x l5: %08x l6: %08x l7: %08x\n",
 166               r_w.locals[0], r_w.locals[1], r_w.locals[2], r_w.locals[3],
 167               r_w.locals[4], r_w.locals[5], r_w.locals[6], r_w.locals[7]);
 168        printk("i0: %08x i1: %08x i2: %08x i3: %08x "
 169               "i4: %08x i5: %08x i6: %08x i7: %08x\n",
 170               r_w.ins[0], r_w.ins[1], r_w.ins[2], r_w.ins[3],
 171               r_w.ins[4], r_w.ins[5], r_w.ins[6], r_w.ins[7]);
 172}
 173#else
 174#define show_regwindow32(regs)  do { } while (0)
 175#endif
 176
 177static void show_regwindow(struct pt_regs *regs)
 178{
 179        struct reg_window __user *rw;
 180        struct reg_window *rwk;
 181        struct reg_window r_w;
 182        mm_segment_t old_fs;
 183
 184        if ((regs->tstate & TSTATE_PRIV) || !(test_thread_flag(TIF_32BIT))) {
 185                __asm__ __volatile__ ("flushw");
 186                rw = (struct reg_window __user *)
 187                        (regs->u_regs[14] + STACK_BIAS);
 188                rwk = (struct reg_window *)
 189                        (regs->u_regs[14] + STACK_BIAS);
 190                if (!(regs->tstate & TSTATE_PRIV)) {
 191                        old_fs = get_fs();
 192                        set_fs (USER_DS);
 193                        if (copy_from_user (&r_w, rw, sizeof(r_w))) {
 194                                set_fs (old_fs);
 195                                return;
 196                        }
 197                        rwk = &r_w;
 198                        set_fs (old_fs);                        
 199                }
 200        } else {
 201                show_regwindow32(regs);
 202                return;
 203        }
 204        printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n",
 205               rwk->locals[0], rwk->locals[1], rwk->locals[2], rwk->locals[3]);
 206        printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
 207               rwk->locals[4], rwk->locals[5], rwk->locals[6], rwk->locals[7]);
 208        printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n",
 209               rwk->ins[0], rwk->ins[1], rwk->ins[2], rwk->ins[3]);
 210        printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n",
 211               rwk->ins[4], rwk->ins[5], rwk->ins[6], rwk->ins[7]);
 212        if (regs->tstate & TSTATE_PRIV)
 213                printk("I7: <%pS>\n", (void *) rwk->ins[7]);
 214}
 215
 216void show_regs(struct pt_regs *regs)
 217{
 218        printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x    %s\n", regs->tstate,
 219               regs->tpc, regs->tnpc, regs->y, print_tainted());
 220        printk("TPC: <%pS>\n", (void *) regs->tpc);
 221        printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
 222               regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
 223               regs->u_regs[3]);
 224        printk("g4: %016lx g5: %016lx g6: %016lx g7: %016lx\n",
 225               regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
 226               regs->u_regs[7]);
 227        printk("o0: %016lx o1: %016lx o2: %016lx o3: %016lx\n",
 228               regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
 229               regs->u_regs[11]);
 230        printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n",
 231               regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
 232               regs->u_regs[15]);
 233        printk("RPC: <%pS>\n", (void *) regs->u_regs[15]);
 234        show_regwindow(regs);
 235}
 236
 237struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
 238static DEFINE_SPINLOCK(global_reg_snapshot_lock);
 239
 240static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
 241                              int this_cpu)
 242{
 243        flushw_all();
 244
 245        global_reg_snapshot[this_cpu].tstate = regs->tstate;
 246        global_reg_snapshot[this_cpu].tpc = regs->tpc;
 247        global_reg_snapshot[this_cpu].tnpc = regs->tnpc;
 248        global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
 249
 250        if (regs->tstate & TSTATE_PRIV) {
 251                struct thread_info *tp = current_thread_info();
 252                struct reg_window *rw;
 253
 254                rw = (struct reg_window *)
 255                        (regs->u_regs[UREG_FP] + STACK_BIAS);
 256                if (kstack_valid(tp, (unsigned long) rw)) {
 257                        global_reg_snapshot[this_cpu].i7 = rw->ins[7];
 258                        rw = (struct reg_window *)
 259                                (rw->ins[6] + STACK_BIAS);
 260                        if (kstack_valid(tp, (unsigned long) rw))
 261                                global_reg_snapshot[this_cpu].rpc = rw->ins[7];
 262                }
 263        } else {
 264                global_reg_snapshot[this_cpu].i7 = 0;
 265                global_reg_snapshot[this_cpu].rpc = 0;
 266        }
 267        global_reg_snapshot[this_cpu].thread = tp;
 268}
 269
 270/* In order to avoid hangs we do not try to synchronize with the
 271 * global register dump client cpus.  The last store they make is to
 272 * the thread pointer, so do a short poll waiting for that to become
 273 * non-NULL.
 274 */
 275static void __global_reg_poll(struct global_reg_snapshot *gp)
 276{
 277        int limit = 0;
 278
 279        while (!gp->thread && ++limit < 100) {
 280                barrier();
 281                udelay(1);
 282        }
 283}
 284
 285void __trigger_all_cpu_backtrace(void)
 286{
 287        struct thread_info *tp = current_thread_info();
 288        struct pt_regs *regs = get_irq_regs();
 289        unsigned long flags;
 290        int this_cpu, cpu;
 291
 292        if (!regs)
 293                regs = tp->kregs;
 294
 295        spin_lock_irqsave(&global_reg_snapshot_lock, flags);
 296
 297        memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
 298
 299        this_cpu = raw_smp_processor_id();
 300
 301        __global_reg_self(tp, regs, this_cpu);
 302
 303        smp_fetch_global_regs();
 304
 305        for_each_online_cpu(cpu) {
 306                struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
 307                struct thread_info *tp;
 308
 309                __global_reg_poll(gp);
 310
 311                tp = gp->thread;
 312                printk("%c CPU[%3d]: TSTATE[%016lx] TPC[%016lx] TNPC[%016lx] TASK[%s:%d]\n",
 313                       (cpu == this_cpu ? '*' : ' '), cpu,
 314                       gp->tstate, gp->tpc, gp->tnpc,
 315                       ((tp && tp->task) ? tp->task->comm : "NULL"),
 316                       ((tp && tp->task) ? tp->task->pid : -1));
 317
 318                if (gp->tstate & TSTATE_PRIV) {
 319                        printk("             TPC[%pS] O7[%pS] I7[%pS] RPC[%pS]\n",
 320                               (void *) gp->tpc,
 321                               (void *) gp->o7,
 322                               (void *) gp->i7,
 323                               (void *) gp->rpc);
 324                } else {
 325                        printk("             TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n",
 326                               gp->tpc, gp->o7, gp->i7, gp->rpc);
 327                }
 328        }
 329
 330        memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
 331
 332        spin_unlock_irqrestore(&global_reg_snapshot_lock, flags);
 333}
 334
 335#ifdef CONFIG_MAGIC_SYSRQ
 336
 337static void sysrq_handle_globreg(int key, struct tty_struct *tty)
 338{
 339        __trigger_all_cpu_backtrace();
 340}
 341
 342static struct sysrq_key_op sparc_globalreg_op = {
 343        .handler        = sysrq_handle_globreg,
 344        .help_msg       = "Globalregs",
 345        .action_msg     = "Show Global CPU Regs",
 346};
 347
 348static int __init sparc_globreg_init(void)
 349{
 350        return register_sysrq_key('y', &sparc_globalreg_op);
 351}
 352
 353core_initcall(sparc_globreg_init);
 354
 355#endif
 356
 357unsigned long thread_saved_pc(struct task_struct *tsk)
 358{
 359        struct thread_info *ti = task_thread_info(tsk);
 360        unsigned long ret = 0xdeadbeefUL;
 361        
 362        if (ti && ti->ksp) {
 363                unsigned long *sp;
 364                sp = (unsigned long *)(ti->ksp + STACK_BIAS);
 365                if (((unsigned long)sp & (sizeof(long) - 1)) == 0UL &&
 366                    sp[14]) {
 367                        unsigned long *fp;
 368                        fp = (unsigned long *)(sp[14] + STACK_BIAS);
 369                        if (((unsigned long)fp & (sizeof(long) - 1)) == 0UL)
 370                                ret = fp[15];
 371                }
 372        }
 373        return ret;
 374}
 375
 376/* Free current thread data structures etc.. */
 377void exit_thread(void)
 378{
 379        struct thread_info *t = current_thread_info();
 380
 381        if (t->utraps) {
 382                if (t->utraps[0] < 2)
 383                        kfree (t->utraps);
 384                else
 385                        t->utraps[0]--;
 386        }
 387
 388        if (test_and_clear_thread_flag(TIF_PERFCTR)) {
 389                t->user_cntd0 = t->user_cntd1 = NULL;
 390                t->pcr_reg = 0;
 391                write_pcr(0);
 392        }
 393}
 394
 395void flush_thread(void)
 396{
 397        struct thread_info *t = current_thread_info();
 398        struct mm_struct *mm;
 399
 400        if (test_ti_thread_flag(t, TIF_ABI_PENDING)) {
 401                clear_ti_thread_flag(t, TIF_ABI_PENDING);
 402                if (test_ti_thread_flag(t, TIF_32BIT))
 403                        clear_ti_thread_flag(t, TIF_32BIT);
 404                else
 405                        set_ti_thread_flag(t, TIF_32BIT);
 406        }
 407
 408        mm = t->task->mm;
 409        if (mm)
 410                tsb_context_switch(mm);
 411
 412        set_thread_wsaved(0);
 413
 414        /* Turn off performance counters if on. */
 415        if (test_and_clear_thread_flag(TIF_PERFCTR)) {
 416                t->user_cntd0 = t->user_cntd1 = NULL;
 417                t->pcr_reg = 0;
 418                write_pcr(0);
 419        }
 420
 421        /* Clear FPU register state. */
 422        t->fpsaved[0] = 0;
 423        
 424        if (get_thread_current_ds() != ASI_AIUS)
 425                set_fs(USER_DS);
 426}
 427
 428/* It's a bit more tricky when 64-bit tasks are involved... */
 429static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
 430{
 431        unsigned long fp, distance, rval;
 432
 433        if (!(test_thread_flag(TIF_32BIT))) {
 434                csp += STACK_BIAS;
 435                psp += STACK_BIAS;
 436                __get_user(fp, &(((struct reg_window __user *)psp)->ins[6]));
 437                fp += STACK_BIAS;
 438        } else
 439                __get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6]));
 440
 441        /* Now 8-byte align the stack as this is mandatory in the
 442         * Sparc ABI due to how register windows work.  This hides
 443         * the restriction from thread libraries etc.  -DaveM
 444         */
 445        csp &= ~7UL;
 446
 447        distance = fp - psp;
 448        rval = (csp - distance);
 449        if (copy_in_user((void __user *) rval, (void __user *) psp, distance))
 450                rval = 0;
 451        else if (test_thread_flag(TIF_32BIT)) {
 452                if (put_user(((u32)csp),
 453                             &(((struct reg_window32 __user *)rval)->ins[6])))
 454                        rval = 0;
 455        } else {
 456                if (put_user(((u64)csp - STACK_BIAS),
 457                             &(((struct reg_window __user *)rval)->ins[6])))
 458                        rval = 0;
 459                else
 460                        rval = rval - STACK_BIAS;
 461        }
 462
 463        return rval;
 464}
 465
 466/* Standard stuff. */
 467static inline void shift_window_buffer(int first_win, int last_win,
 468                                       struct thread_info *t)
 469{
 470        int i;
 471
 472        for (i = first_win; i < last_win; i++) {
 473                t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
 474                memcpy(&t->reg_window[i], &t->reg_window[i+1],
 475                       sizeof(struct reg_window));
 476        }
 477}
 478
 479void synchronize_user_stack(void)
 480{
 481        struct thread_info *t = current_thread_info();
 482        unsigned long window;
 483
 484        flush_user_windows();
 485        if ((window = get_thread_wsaved()) != 0) {
 486                int winsize = sizeof(struct reg_window);
 487                int bias = 0;
 488
 489                if (test_thread_flag(TIF_32BIT))
 490                        winsize = sizeof(struct reg_window32);
 491                else
 492                        bias = STACK_BIAS;
 493
 494                window -= 1;
 495                do {
 496                        unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
 497                        struct reg_window *rwin = &t->reg_window[window];
 498
 499                        if (!copy_to_user((char __user *)sp, rwin, winsize)) {
 500                                shift_window_buffer(window, get_thread_wsaved() - 1, t);
 501                                set_thread_wsaved(get_thread_wsaved() - 1);
 502                        }
 503                } while (window--);
 504        }
 505}
 506
 507static void stack_unaligned(unsigned long sp)
 508{
 509        siginfo_t info;
 510
 511        info.si_signo = SIGBUS;
 512        info.si_errno = 0;
 513        info.si_code = BUS_ADRALN;
 514        info.si_addr = (void __user *) sp;
 515        info.si_trapno = 0;
 516        force_sig_info(SIGBUS, &info, current);
 517}
 518
 519void fault_in_user_windows(void)
 520{
 521        struct thread_info *t = current_thread_info();
 522        unsigned long window;
 523        int winsize = sizeof(struct reg_window);
 524        int bias = 0;
 525
 526        if (test_thread_flag(TIF_32BIT))
 527                winsize = sizeof(struct reg_window32);
 528        else
 529                bias = STACK_BIAS;
 530
 531        flush_user_windows();
 532        window = get_thread_wsaved();
 533
 534        if (likely(window != 0)) {
 535                window -= 1;
 536                do {
 537                        unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
 538                        struct reg_window *rwin = &t->reg_window[window];
 539
 540                        if (unlikely(sp & 0x7UL))
 541                                stack_unaligned(sp);
 542
 543                        if (unlikely(copy_to_user((char __user *)sp,
 544                                                  rwin, winsize)))
 545                                goto barf;
 546                } while (window--);
 547        }
 548        set_thread_wsaved(0);
 549        return;
 550
 551barf:
 552        set_thread_wsaved(window + 1);
 553        do_exit(SIGILL);
 554}
 555
 556asmlinkage long sparc_do_fork(unsigned long clone_flags,
 557                              unsigned long stack_start,
 558                              struct pt_regs *regs,
 559                              unsigned long stack_size)
 560{
 561        int __user *parent_tid_ptr, *child_tid_ptr;
 562        unsigned long orig_i1 = regs->u_regs[UREG_I1];
 563        long ret;
 564
 565#ifdef CONFIG_COMPAT
 566        if (test_thread_flag(TIF_32BIT)) {
 567                parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]);
 568                child_tid_ptr = compat_ptr(regs->u_regs[UREG_I4]);
 569        } else
 570#endif
 571        {
 572                parent_tid_ptr = (int __user *) regs->u_regs[UREG_I2];
 573                child_tid_ptr = (int __user *) regs->u_regs[UREG_I4];
 574        }
 575
 576        ret = do_fork(clone_flags, stack_start,
 577                      regs, stack_size,
 578                      parent_tid_ptr, child_tid_ptr);
 579
 580        /* If we get an error and potentially restart the system
 581         * call, we're screwed because copy_thread() clobbered
 582         * the parent's %o1.  So detect that case and restore it
 583         * here.
 584         */
 585        if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
 586                regs->u_regs[UREG_I1] = orig_i1;
 587
 588        return ret;
 589}
 590
 591/* Copy a Sparc thread.  The fork() return value conventions
 592 * under SunOS are nothing short of bletcherous:
 593 * Parent -->  %o0 == childs  pid, %o1 == 0
 594 * Child  -->  %o0 == parents pid, %o1 == 1
 595 */
 596int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 597                unsigned long unused,
 598                struct task_struct *p, struct pt_regs *regs)
 599{
 600        struct thread_info *t = task_thread_info(p);
 601        struct sparc_stackf *parent_sf;
 602        unsigned long child_stack_sz;
 603        char *child_trap_frame;
 604        int kernel_thread;
 605
 606        kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
 607        parent_sf = ((struct sparc_stackf *) regs) - 1;
 608
 609        /* Calculate offset to stack_frame & pt_regs */
 610        child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
 611                          (kernel_thread ? STACKFRAME_SZ : 0));
 612        child_trap_frame = (task_stack_page(p) +
 613                            (THREAD_SIZE - child_stack_sz));
 614        memcpy(child_trap_frame, parent_sf, child_stack_sz);
 615
 616        t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
 617                                 (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
 618                (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
 619        t->new_child = 1;
 620        t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
 621        t->kregs = (struct pt_regs *) (child_trap_frame +
 622                                       sizeof(struct sparc_stackf));
 623        t->fpsaved[0] = 0;
 624
 625        if (kernel_thread) {
 626                struct sparc_stackf *child_sf = (struct sparc_stackf *)
 627                        (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));
 628
 629                /* Zero terminate the stack backtrace.  */
 630                child_sf->fp = NULL;
 631                t->kregs->u_regs[UREG_FP] =
 632                  ((unsigned long) child_sf) - STACK_BIAS;
 633
 634                /* Special case, if we are spawning a kernel thread from
 635                 * a userspace task (usermode helper, NFS or similar), we
 636                 * must disable performance counters in the child because
 637                 * the address space and protection realm are changing.
 638                 */
 639                if (t->flags & _TIF_PERFCTR) {
 640                        t->user_cntd0 = t->user_cntd1 = NULL;
 641                        t->pcr_reg = 0;
 642                        t->flags &= ~_TIF_PERFCTR;
 643                }
 644                t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
 645                t->kregs->u_regs[UREG_G6] = (unsigned long) t;
 646                t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
 647        } else {
 648                if (t->flags & _TIF_32BIT) {
 649                        sp &= 0x00000000ffffffffUL;
 650                        regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 651                }
 652                t->kregs->u_regs[UREG_FP] = sp;
 653                t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT);
 654                if (sp != regs->u_regs[UREG_FP]) {
 655                        unsigned long csp;
 656
 657                        csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
 658                        if (!csp)
 659                                return -EFAULT;
 660                        t->kregs->u_regs[UREG_FP] = csp;
 661                }
 662                if (t->utraps)
 663                        t->utraps[0]++;
 664        }
 665
 666        /* Set the return value for the child. */
 667        t->kregs->u_regs[UREG_I0] = current->pid;
 668        t->kregs->u_regs[UREG_I1] = 1;
 669
 670        /* Set the second return value for the parent. */
 671        regs->u_regs[UREG_I1] = 0;
 672
 673        if (clone_flags & CLONE_SETTLS)
 674                t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
 675
 676        return 0;
 677}
 678
 679/*
 680 * This is the mechanism for creating a new kernel thread.
 681 *
 682 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
 683 * who haven't done an "execve()") should use this: it will work within
 684 * a system call from a "real" process, but the process memory space will
 685 * not be freed until both the parent and the child have exited.
 686 */
 687pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 688{
 689        long retval;
 690
 691        /* If the parent runs before fn(arg) is called by the child,
 692         * the input registers of this function can be clobbered.
 693         * So we stash 'fn' and 'arg' into global registers which
 694         * will not be modified by the parent.
 695         */
 696        __asm__ __volatile__("mov %4, %%g2\n\t"    /* Save FN into global */
 697                             "mov %5, %%g3\n\t"    /* Save ARG into global */
 698                             "mov %1, %%g1\n\t"    /* Clone syscall nr. */
 699                             "mov %2, %%o0\n\t"    /* Clone flags. */
 700                             "mov 0, %%o1\n\t"     /* usp arg == 0 */
 701                             "t 0x6d\n\t"          /* Linux/Sparc clone(). */
 702                             "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
 703                             " mov %%o0, %0\n\t"
 704                             "jmpl %%g2, %%o7\n\t"   /* Call the function. */
 705                             " mov %%g3, %%o0\n\t"   /* Set arg in delay. */
 706                             "mov %3, %%g1\n\t"
 707                             "t 0x6d\n\t"          /* Linux/Sparc exit(). */
 708                             /* Notreached by child. */
 709                             "1:" :
 710                             "=r" (retval) :
 711                             "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
 712                             "i" (__NR_exit),  "r" (fn), "r" (arg) :
 713                             "g1", "g2", "g3", "o0", "o1", "memory", "cc");
 714        return retval;
 715}
 716
 717typedef struct {
 718        union {
 719                unsigned int    pr_regs[32];
 720                unsigned long   pr_dregs[16];
 721        } pr_fr;
 722        unsigned int __unused;
 723        unsigned int    pr_fsr;
 724        unsigned char   pr_qcnt;
 725        unsigned char   pr_q_entrysize;
 726        unsigned char   pr_en;
 727        unsigned int    pr_q[64];
 728} elf_fpregset_t32;
 729
 730/*
 731 * fill in the fpu structure for a core dump.
 732 */
 733int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 734{
 735        unsigned long *kfpregs = current_thread_info()->fpregs;
 736        unsigned long fprs = current_thread_info()->fpsaved[0];
 737
 738        if (test_thread_flag(TIF_32BIT)) {
 739                elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
 740
 741                if (fprs & FPRS_DL)
 742                        memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs,
 743                               sizeof(unsigned int) * 32);
 744                else
 745                        memset(&fpregs32->pr_fr.pr_regs[0], 0,
 746                               sizeof(unsigned int) * 32);
 747                fpregs32->pr_qcnt = 0;
 748                fpregs32->pr_q_entrysize = 8;
 749                memset(&fpregs32->pr_q[0], 0,
 750                       (sizeof(unsigned int) * 64));
 751                if (fprs & FPRS_FEF) {
 752                        fpregs32->pr_fsr = (unsigned int) current_thread_info()->xfsr[0];
 753                        fpregs32->pr_en = 1;
 754                } else {
 755                        fpregs32->pr_fsr = 0;
 756                        fpregs32->pr_en = 0;
 757                }
 758        } else {
 759                if(fprs & FPRS_DL)
 760                        memcpy(&fpregs->pr_regs[0], kfpregs,
 761                               sizeof(unsigned int) * 32);
 762                else
 763                        memset(&fpregs->pr_regs[0], 0,
 764                               sizeof(unsigned int) * 32);
 765                if(fprs & FPRS_DU)
 766                        memcpy(&fpregs->pr_regs[16], kfpregs+16,
 767                               sizeof(unsigned int) * 32);
 768                else
 769                        memset(&fpregs->pr_regs[16], 0,
 770                               sizeof(unsigned int) * 32);
 771                if(fprs & FPRS_FEF) {
 772                        fpregs->pr_fsr = current_thread_info()->xfsr[0];
 773                        fpregs->pr_gsr = current_thread_info()->gsr[0];
 774                } else {
 775                        fpregs->pr_fsr = fpregs->pr_gsr = 0;
 776                }
 777                fpregs->pr_fprs = fprs;
 778        }
 779        return 1;
 780}
 781
 782/*
 783 * sparc_execve() executes a new program after the asm stub has set
 784 * things up for us.  This should basically do what I want it to.
 785 */
 786asmlinkage int sparc_execve(struct pt_regs *regs)
 787{
 788        int error, base = 0;
 789        char *filename;
 790
 791        /* User register window flush is done by entry.S */
 792
 793        /* Check for indirect call. */
 794        if (regs->u_regs[UREG_G1] == 0)
 795                base = 1;
 796
 797        filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
 798        error = PTR_ERR(filename);
 799        if (IS_ERR(filename))
 800                goto out;
 801        error = do_execve(filename,
 802                          (char __user * __user *)
 803                          regs->u_regs[base + UREG_I1],
 804                          (char __user * __user *)
 805                          regs->u_regs[base + UREG_I2], regs);
 806        putname(filename);
 807        if (!error) {
 808                fprs_write(0);
 809                current_thread_info()->xfsr[0] = 0;
 810                current_thread_info()->fpsaved[0] = 0;
 811                regs->tstate &= ~TSTATE_PEF;
 812        }
 813out:
 814        return error;
 815}
 816
 817unsigned long get_wchan(struct task_struct *task)
 818{
 819        unsigned long pc, fp, bias = 0;
 820        struct thread_info *tp;
 821        struct reg_window *rw;
 822        unsigned long ret = 0;
 823        int count = 0; 
 824
 825        if (!task || task == current ||
 826            task->state == TASK_RUNNING)
 827                goto out;
 828
 829        tp = task_thread_info(task);
 830        bias = STACK_BIAS;
 831        fp = task_thread_info(task)->ksp + bias;
 832
 833        do {
 834                if (!kstack_valid(tp, fp))
 835                        break;
 836                rw = (struct reg_window *) fp;
 837                pc = rw->ins[7];
 838                if (!in_sched_functions(pc)) {
 839                        ret = pc;
 840                        goto out;
 841                }
 842                fp = rw->ins[6] + bias;
 843        } while (++count < 16);
 844
 845out:
 846        return ret;
 847}
 848
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.