linux/arch/s390/kernel/process.c
<<
>>
Prefs
   1/*
   2 * This file handles the architecture dependent parts of process handling.
   3 *
   4 *    Copyright IBM Corp. 1999,2009
   5 *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
   6 *               Hartmut Penner <hp@de.ibm.com>,
   7 *               Denis Joseph Barrow,
   8 */
   9
  10#include <linux/compiler.h>
  11#include <linux/cpu.h>
  12#include <linux/sched.h>
  13#include <linux/kernel.h>
  14#include <linux/mm.h>
  15#include <linux/elfcore.h>
  16#include <linux/smp.h>
  17#include <linux/slab.h>
  18#include <linux/interrupt.h>
  19#include <linux/tick.h>
  20#include <linux/personality.h>
  21#include <linux/syscalls.h>
  22#include <linux/compat.h>
  23#include <linux/kprobes.h>
  24#include <linux/random.h>
  25#include <linux/module.h>
  26#include <asm/io.h>
  27#include <asm/processor.h>
  28#include <asm/irq.h>
  29#include <asm/timer.h>
  30#include <asm/nmi.h>
  31#include <asm/smp.h>
  32#include <asm/switch_to.h>
  33#include "entry.h"
  34
  35asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
  36
  37/*
  38 * Return saved PC of a blocked thread. used in kernel/sched.
  39 * resume in entry.S does not create a new stack frame, it
  40 * just stores the registers %r6-%r15 to the frame given by
  41 * schedule. We want to return the address of the caller of
  42 * schedule, so we have to walk the backchain one time to
  43 * find the frame schedule() store its return address.
  44 */
  45unsigned long thread_saved_pc(struct task_struct *tsk)
  46{
  47        struct stack_frame *sf, *low, *high;
  48
  49        if (!tsk || !task_stack_page(tsk))
  50                return 0;
  51        low = task_stack_page(tsk);
  52        high = (struct stack_frame *) task_pt_regs(tsk);
  53        sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN);
  54        if (sf <= low || sf > high)
  55                return 0;
  56        sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
  57        if (sf <= low || sf > high)
  58                return 0;
  59        return sf->gprs[8];
  60}
  61
  62/*
  63 * The idle loop on a S390...
  64 */
  65static void default_idle(void)
  66{
  67        if (cpu_is_offline(smp_processor_id()))
  68                cpu_die();
  69        local_irq_disable();
  70        if (need_resched()) {
  71                local_irq_enable();
  72                return;
  73        }
  74        local_mcck_disable();
  75        if (test_thread_flag(TIF_MCCK_PENDING)) {
  76                local_mcck_enable();
  77                local_irq_enable();
  78                return;
  79        }
  80        /* Halt the cpu and keep track of cpu time accounting. */
  81        vtime_stop_cpu();
  82}
  83
  84void cpu_idle(void)
  85{
  86        for (;;) {
  87                tick_nohz_idle_enter();
  88                rcu_idle_enter();
  89                while (!need_resched() && !test_thread_flag(TIF_MCCK_PENDING))
  90                        default_idle();
  91                rcu_idle_exit();
  92                tick_nohz_idle_exit();
  93                if (test_thread_flag(TIF_MCCK_PENDING))
  94                        s390_handle_mcck();
  95                schedule_preempt_disabled();
  96        }
  97}
  98
  99extern void __kprobes kernel_thread_starter(void);
 100
 101asm(
 102        ".section .kprobes.text, \"ax\"\n"
 103        ".global kernel_thread_starter\n"
 104        "kernel_thread_starter:\n"
 105        "    la    2,0(10)\n"
 106        "    basr  14,9\n"
 107        "    la    2,0\n"
 108        "    br    11\n"
 109        ".previous\n");
 110
 111int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 112{
 113        struct pt_regs regs;
 114
 115        memset(&regs, 0, sizeof(regs));
 116        regs.psw.mask = psw_kernel_bits |
 117                PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
 118        regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
 119        regs.gprs[9] = (unsigned long) fn;
 120        regs.gprs[10] = (unsigned long) arg;
 121        regs.gprs[11] = (unsigned long) do_exit;
 122        regs.orig_gpr2 = -1;
 123
 124        /* Ok, create the new process.. */
 125        return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
 126                       0, &regs, 0, NULL, NULL);
 127}
 128EXPORT_SYMBOL(kernel_thread);
 129
 130/*
 131 * Free current thread data structures etc..
 132 */
 133void exit_thread(void)
 134{
 135}
 136
 137void flush_thread(void)
 138{
 139}
 140
 141void release_thread(struct task_struct *dead_task)
 142{
 143}
 144
 145int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 146                unsigned long unused,
 147                struct task_struct *p, struct pt_regs *regs)
 148{
 149        struct thread_info *ti;
 150        struct fake_frame
 151        {
 152                struct stack_frame sf;
 153                struct pt_regs childregs;
 154        } *frame;
 155
 156        frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
 157        p->thread.ksp = (unsigned long) frame;
 158        /* Store access registers to kernel stack of new process. */
 159        frame->childregs = *regs;
 160        frame->childregs.gprs[2] = 0;   /* child returns 0 on fork. */
 161        frame->childregs.gprs[15] = new_stackp;
 162        frame->sf.back_chain = 0;
 163
 164        /* new return point is ret_from_fork */
 165        frame->sf.gprs[8] = (unsigned long) ret_from_fork;
 166
 167        /* fake return stack for resume(), don't go back to schedule */
 168        frame->sf.gprs[9] = (unsigned long) frame;
 169
 170        /* Save access registers to new thread structure. */
 171        save_access_regs(&p->thread.acrs[0]);
 172
 173#ifndef CONFIG_64BIT
 174        /*
 175         * save fprs to current->thread.fp_regs to merge them with
 176         * the emulated registers and then copy the result to the child.
 177         */
 178        save_fp_regs(&current->thread.fp_regs);
 179        memcpy(&p->thread.fp_regs, &current->thread.fp_regs,
 180               sizeof(s390_fp_regs));
 181        /* Set a new TLS ?  */
 182        if (clone_flags & CLONE_SETTLS)
 183                p->thread.acrs[0] = regs->gprs[6];
 184#else /* CONFIG_64BIT */
 185        /* Save the fpu registers to new thread structure. */
 186        save_fp_regs(&p->thread.fp_regs);
 187        /* Set a new TLS ?  */
 188        if (clone_flags & CLONE_SETTLS) {
 189                if (is_compat_task()) {
 190                        p->thread.acrs[0] = (unsigned int) regs->gprs[6];
 191                } else {
 192                        p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
 193                        p->thread.acrs[1] = (unsigned int) regs->gprs[6];
 194                }
 195        }
 196#endif /* CONFIG_64BIT */
 197        /* start new process with ar4 pointing to the correct address space */
 198        p->thread.mm_segment = get_fs();
 199        /* Don't copy debug registers */
 200        memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
 201        memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
 202        clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
 203        clear_tsk_thread_flag(p, TIF_PER_TRAP);
 204        /* Initialize per thread user and system timer values */
 205        ti = task_thread_info(p);
 206        ti->user_timer = 0;
 207        ti->system_timer = 0;
 208        return 0;
 209}
 210
 211SYSCALL_DEFINE0(fork)
 212{
 213        struct pt_regs *regs = task_pt_regs(current);
 214        return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL);
 215}
 216
 217SYSCALL_DEFINE4(clone, unsigned long, newsp, unsigned long, clone_flags,
 218                int __user *, parent_tidptr, int __user *, child_tidptr)
 219{
 220        struct pt_regs *regs = task_pt_regs(current);
 221
 222        if (!newsp)
 223                newsp = regs->gprs[15];
 224        return do_fork(clone_flags, newsp, regs, 0,
 225                       parent_tidptr, child_tidptr);
 226}
 227
 228/*
 229 * This is trivial, and on the face of it looks like it
 230 * could equally well be done in user mode.
 231 *
 232 * Not so, for quite unobvious reasons - register pressure.
 233 * In user mode vfork() cannot have a stack frame, and if
 234 * done by calling the "clone()" system call directly, you
 235 * do not have enough call-clobbered registers to hold all
 236 * the information you need.
 237 */
 238SYSCALL_DEFINE0(vfork)
 239{
 240        struct pt_regs *regs = task_pt_regs(current);
 241        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
 242                       regs->gprs[15], regs, 0, NULL, NULL);
 243}
 244
 245asmlinkage void execve_tail(void)
 246{
 247        current->thread.fp_regs.fpc = 0;
 248        if (MACHINE_HAS_IEEE)
 249                asm volatile("sfpc %0,%0" : : "d" (0));
 250}
 251
 252/*
 253 * sys_execve() executes a new program.
 254 */
 255SYSCALL_DEFINE3(execve, const char __user *, name,
 256                const char __user *const __user *, argv,
 257                const char __user *const __user *, envp)
 258{
 259        struct pt_regs *regs = task_pt_regs(current);
 260        char *filename;
 261        long rc;
 262
 263        filename = getname(name);
 264        rc = PTR_ERR(filename);
 265        if (IS_ERR(filename))
 266                return rc;
 267        rc = do_execve(filename, argv, envp, regs);
 268        if (rc)
 269                goto out;
 270        execve_tail();
 271        rc = regs->gprs[2];
 272out:
 273        putname(filename);
 274        return rc;
 275}
 276
 277/*
 278 * fill in the FPU structure for a core dump.
 279 */
 280int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
 281{
 282#ifndef CONFIG_64BIT
 283        /*
 284         * save fprs to current->thread.fp_regs to merge them with
 285         * the emulated registers and then copy the result to the dump.
 286         */
 287        save_fp_regs(&current->thread.fp_regs);
 288        memcpy(fpregs, &current->thread.fp_regs, sizeof(s390_fp_regs));
 289#else /* CONFIG_64BIT */
 290        save_fp_regs(fpregs);
 291#endif /* CONFIG_64BIT */
 292        return 1;
 293}
 294EXPORT_SYMBOL(dump_fpu);
 295
 296unsigned long get_wchan(struct task_struct *p)
 297{
 298        struct stack_frame *sf, *low, *high;
 299        unsigned long return_address;
 300        int count;
 301
 302        if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
 303                return 0;
 304        low = task_stack_page(p);
 305        high = (struct stack_frame *) task_pt_regs(p);
 306        sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN);
 307        if (sf <= low || sf > high)
 308                return 0;
 309        for (count = 0; count < 16; count++) {
 310                sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
 311                if (sf <= low || sf > high)
 312                        return 0;
 313                return_address = sf->gprs[8] & PSW_ADDR_INSN;
 314                if (!in_sched_functions(return_address))
 315                        return return_address;
 316        }
 317        return 0;
 318}
 319
 320unsigned long arch_align_stack(unsigned long sp)
 321{
 322        if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
 323                sp -= get_random_int() & ~PAGE_MASK;
 324        return sp & ~0xf;
 325}
 326
 327static inline unsigned long brk_rnd(void)
 328{
 329        /* 8MB for 32bit, 1GB for 64bit */
 330        if (is_32bit_task())
 331                return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
 332        else
 333                return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
 334}
 335
 336unsigned long arch_randomize_brk(struct mm_struct *mm)
 337{
 338        unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
 339
 340        if (ret < mm->brk)
 341                return mm->brk;
 342        return ret;
 343}
 344
 345unsigned long randomize_et_dyn(unsigned long base)
 346{
 347        unsigned long ret = PAGE_ALIGN(base + brk_rnd());
 348
 349        if (!(current->flags & PF_RANDOMIZE))
 350                return base;
 351        if (ret < base)
 352                return base;
 353        return ret;
 354}
 355