linux-old/arch/s390x/kernel/process.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/process.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
   7 *               Hartmut Penner (hp@de.ibm.com),
   8 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
   9 *
  10 *  Derived from "arch/i386/kernel/process.c"
  11 *    Copyright (C) 1995, Linus Torvalds
  12 */
  13
  14/*
  15 * This file handles the architecture-dependent parts of process handling..
  16 */
  17
  18#define __KERNEL_SYSCALLS__
  19#include <stdarg.h>
  20
  21#include <linux/config.h>
  22#include <linux/errno.h>
  23#include <linux/sched.h>
  24#include <linux/kernel.h>
  25#include <linux/mm.h>
  26#include <linux/smp.h>
  27#include <linux/smp_lock.h>
  28#include <linux/stddef.h>
  29#include <linux/unistd.h>
  30#include <linux/ptrace.h>
  31#include <linux/slab.h>
  32#include <linux/vmalloc.h>
  33#include <linux/user.h>
  34#include <linux/a.out.h>
  35#include <linux/interrupt.h>
  36#include <linux/delay.h>
  37#include <linux/reboot.h>
  38#include <linux/init.h>
  39
  40#include <asm/uaccess.h>
  41#include <asm/pgtable.h>
  42#include <asm/system.h>
  43#include <asm/io.h>
  44#include <asm/processor.h>
  45#include <asm/irq.h>
  46
  47asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  48
  49/*
  50 * The idle loop on a S390...
  51 */
  52
  53int cpu_idle(void *unused)
  54{
  55        psw_t wait_psw;
  56        unsigned long reg;
  57
  58        /* endless idle loop with no priority at all */
  59        init_idle();
  60        current->nice = 20;
  61        current->counter = -100;
  62        while (1) {
  63                __cli();
  64                if (current->need_resched) {
  65                        __sti();
  66                        schedule();
  67                        check_pgt_cache();
  68                        continue;
  69                }
  70
  71                /* 
  72                 * Wait for external, I/O or machine check interrupt and
  73                 * switch of machine check bit after the wait has ended.
  74                 */
  75                wait_psw.mask = _WAIT_PSW_MASK;
  76                asm volatile (
  77                        "    larl  %0,0f\n"
  78                        "    stg   %0,8(%1)\n"
  79                        "    lpswe 0(%1)\n"
  80                        "0:  larl  %0,1f\n"
  81                        "    stg   %0,8(%1)\n"
  82                        "    ni    1(%1),0xf9\n"
  83                        "    lpswe 0(%1)\n"
  84                        "1:"
  85                        : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
  86        }
  87}
  88
  89extern void show_registers(struct pt_regs *regs);
  90extern void show_trace(unsigned long *sp);
  91
  92void show_regs(struct pt_regs *regs)
  93{
  94        struct task_struct *tsk = current;
  95
  96        printk("CPU:    %d    %s\n", tsk->processor, print_tainted());
  97        printk("Process %s (pid: %d, task: %016lx, ksp: %016lx)\n",
  98               current->comm, current->pid, (unsigned long) tsk,
  99               tsk->thread.ksp);
 100
 101        show_registers(regs);
 102        /* Show stack backtrace if pt_regs is from kernel mode */
 103        if (!(regs->psw.mask & PSW_PROBLEM_STATE))
 104                show_trace((unsigned long *) regs->gprs[15]);
 105}
 106
 107int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 108{
 109        int clone_arg = flags | CLONE_VM;
 110        int retval;
 111
 112        __asm__ __volatile__(
 113                "     slgr  2,2\n"
 114                "     lgr   3,%1\n"
 115                "     lg    4,%6\n"     /* load kernel stack ptr of parent */
 116                "     svc   %b2\n"                     /* Linux system call*/
 117                "     clg   4,%6\n"    /* compare ksp's: child or parent ? */
 118                "     je    0f\n"                          /* parent - jump*/
 119                "     lg    15,%6\n"            /* fix kernel stack pointer*/
 120                "     aghi  15,%7\n"
 121                "     xc    0(160,15),0(15)\n"          /* clear save area */
 122                "     lgr   2,%4\n"                        /* load argument*/
 123                "     basr  14,%5\n"                             /* call fn*/
 124                "     svc   %b3\n"                     /* Linux system call*/
 125                "0:   lgr   %0,2"
 126                : "=a" (retval)
 127                : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
 128                  "d" (arg), "a" (fn), "i" (__LC_KERNEL_STACK) ,
 129                  "i" (-STACK_FRAME_OVERHEAD)
 130                : "2", "3", "4" );
 131        return retval;
 132}
 133
 134/*
 135 * Free current thread data structures etc..
 136 */
 137void exit_thread(void)
 138{
 139}
 140
 141void flush_thread(void)
 142{
 143
 144        current->used_math = 0;
 145        current->flags &= ~PF_USEDFPU;
 146}
 147
 148void release_thread(struct task_struct *dead_task)
 149{
 150}
 151
 152int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
 153        unsigned long unused,
 154        struct task_struct * p, struct pt_regs * regs)
 155{
 156        struct stack_frame
 157          {
 158            unsigned long back_chain;
 159            unsigned long eos;
 160            unsigned long glue1;
 161            unsigned long glue2;
 162            unsigned long scratch[2];
 163            unsigned long gprs[10];    /* gprs 6 -15                       */
 164            unsigned long fprs[2];     /* fpr 4 and 6                      */
 165            unsigned long empty[2];
 166            struct pt_regs childregs;
 167          } *frame;
 168
 169        frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1;
 170        p->thread.ksp = (unsigned long) frame;
 171        frame->childregs = *regs;
 172        frame->childregs.gprs[15] = new_stackp;
 173        frame->back_chain = frame->eos = 0;
 174
 175        /* new return point is ret_from_sys_call */
 176        frame->gprs[8] = (unsigned long) &ret_from_fork;
 177
 178        /* fake return stack for resume(), don't go back to schedule */
 179        frame->gprs[9] = (unsigned long) frame;
 180        /* save fprs, if used in last task */
 181        save_fp_regs(&p->thread.fp_regs);
 182        p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
 183        /* start new process with ar4 pointing to the correct address space */
 184        p->thread.ar4 = get_fs().ar4;
 185        /* Don't copy debug registers */
 186        memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
 187        return 0;
 188}
 189
 190/* 
 191 * Allocation and freeing of basic task resources. 
 192 * The task struct and the stack go together.
 193 *
 194 * NOTE: An order-2 allocation can easily fail.  If this
 195 *       happens we fall back to using vmalloc ...
 196 */
 197
 198struct task_struct *alloc_task_struct(void)
 199{
 200        struct task_struct *tsk = __get_free_pages(GFP_KERNEL, 2);
 201        if (!tsk)
 202                tsk = vmalloc(16384);
 203        if (!tsk)
 204                return NULL;
 205
 206        atomic_set((atomic_t *)(tsk + 1), 1);
 207        return tsk;
 208}
 209
 210void free_task_struct(struct task_struct *tsk)
 211{
 212        if (atomic_dec_and_test((atomic_t *)(tsk + 1)))
 213        {
 214                if ((unsigned long)tsk < VMALLOC_START)
 215                        free_pages((unsigned long)tsk, 2);
 216                else
 217                        vfree(tsk);
 218        }
 219}
 220
 221void get_task_struct(struct task_struct *tsk)
 222{
 223        atomic_inc((atomic_t *)(tsk + 1));
 224}
 225
 226
 227asmlinkage int sys_fork(struct pt_regs regs)
 228{
 229        return do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
 230}
 231
 232asmlinkage int sys_clone(struct pt_regs regs)
 233{
 234        unsigned long clone_flags;
 235        unsigned long newsp;
 236
 237        clone_flags = regs.gprs[3];
 238        newsp = regs.orig_gpr2;
 239        if (!newsp)
 240                newsp = regs.gprs[15];
 241        return do_fork(clone_flags, newsp, &regs, 0);
 242}
 243
 244/*
 245 * This is trivial, and on the face of it looks like it
 246 * could equally well be done in user mode.
 247 *
 248 * Not so, for quite unobvious reasons - register pressure.
 249 * In user mode vfork() cannot have a stack frame, and if
 250 * done by calling the "clone()" system call directly, you
 251 * do not have enough call-clobbered registers to hold all
 252 * the information you need.
 253 */
 254asmlinkage int sys_vfork(struct pt_regs regs)
 255{
 256        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
 257                       regs.gprs[15], &regs, 0);
 258}
 259
 260/*
 261 * sys_execve() executes a new program.
 262 */
 263asmlinkage int sys_execve(struct pt_regs regs)
 264{
 265        int error;
 266        char * filename;
 267
 268        filename = getname((char *) regs.orig_gpr2);
 269        error = PTR_ERR(filename);
 270        if (IS_ERR(filename))
 271                goto out;
 272        error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
 273        if (error == 0)
 274        {
 275                current->ptrace &= ~PT_DTRACE;
 276                current->thread.fp_regs.fpc=0;
 277                __asm__ __volatile__
 278                        ("sr  0,0\n\t"
 279                         "sfpc 0,0\n\t"
 280                         : : :"0");
 281        }
 282        putname(filename);
 283out:
 284        return error;
 285}
 286
 287
 288/*
 289 * fill in the FPU structure for a core dump.
 290 */
 291int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
 292{
 293        save_fp_regs(fpregs);
 294        return 1;
 295}
 296
 297/*
 298 * fill in the user structure for a core dump..
 299 */
 300void dump_thread(struct pt_regs * regs, struct user * dump)
 301{
 302
 303/* changed the size calculations - should hopefully work better. lbt */
 304        dump->magic = CMAGIC;
 305        dump->start_code = 0;
 306        dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
 307        dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
 308        dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
 309        dump->u_dsize -= dump->u_tsize;
 310        dump->u_ssize = 0;
 311        if (dump->start_stack < TASK_SIZE)
 312                dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
 313        memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
 314        dump_fpu (regs, &dump->regs.fp_regs);
 315        memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
 316}
 317
 318/*
 319 * These bracket the sleeping functions..
 320 */
 321extern void scheduling_functions_start_here(void);
 322extern void scheduling_functions_end_here(void);
 323#define first_sched     ((unsigned long) scheduling_functions_start_here)
 324#define last_sched      ((unsigned long) scheduling_functions_end_here)
 325
 326unsigned long get_wchan(struct task_struct *p)
 327{
 328        unsigned long r14, r15, bc;
 329        unsigned long stack_page;
 330        int count = 0;
 331        if (!p || p == current || p->state == TASK_RUNNING)
 332                return 0;
 333        stack_page = (unsigned long) p;
 334        r15 = p->thread.ksp;
 335        if (!stack_page || r15 < stack_page || r15 >= 16380+stack_page)
 336                return 0;
 337        bc = *(unsigned long *) r15;
 338        do {
 339                if (bc < stack_page || bc >= 16380+stack_page)
 340                        return 0;
 341                r14 = *(unsigned long *) (bc+112);
 342                if (r14 < first_sched || r14 >= last_sched)
 343                        return r14;
 344                bc = *(unsigned long *) bc;
 345        } while (count++ < 16);
 346        return 0;
 347}
 348#undef last_sched
 349#undef first_sched
 350
 351
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.