linux/arch/arm/kernel/traps.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/traps.c
   3 *
   4 *  Copyright (C) 1995-2002 Russell King
   5 *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 *  'traps.c' handles hardware exceptions after we have saved some state in
  12 *  'linux/arch/arm/lib/traps.S'.  Mostly a debugging aid, but will probably
  13 *  kill the offending process.
  14 */
  15#include <linux/config.h>
  16#include <linux/module.h>
  17#include <linux/signal.h>
  18#include <linux/spinlock.h>
  19#include <linux/personality.h>
  20#include <linux/ptrace.h>
  21#include <linux/kallsyms.h>
  22#include <linux/init.h>
  23
  24#include <asm/atomic.h>
  25#include <asm/cacheflush.h>
  26#include <asm/io.h>
  27#include <asm/system.h>
  28#include <asm/uaccess.h>
  29#include <asm/unistd.h>
  30#include <asm/traps.h>
  31
  32#include "ptrace.h"
  33
  34const char *processor_modes[]=
  35{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
  36  "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
  37  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
  38  "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
  39};
  40
  41static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
  42
  43#ifdef CONFIG_DEBUG_USER
  44unsigned int user_debug;
  45
  46static int __init user_debug_setup(char *str)
  47{
  48        get_option(&str, &user_debug);
  49        return 1;
  50}
  51__setup("user_debug=", user_debug_setup);
  52#endif
  53
  54void dump_backtrace_entry(unsigned long where, unsigned long from)
  55{
  56#ifdef CONFIG_KALLSYMS
  57        printk("[<%08lx>] ", where);
  58        print_symbol("(%s) ", where);
  59        printk("from [<%08lx>] ", from);
  60        print_symbol("(%s)\n", from);
  61#else
  62        printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
  63#endif
  64}
  65
  66/*
  67 * Stack pointers should always be within the kernels view of
  68 * physical memory.  If it is not there, then we can't dump
  69 * out any information relating to the stack.
  70 */
  71static int verify_stack(unsigned long sp)
  72{
  73        if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0))
  74                return -EFAULT;
  75
  76        return 0;
  77}
  78
  79/*
  80 * Dump out the contents of some memory nicely...
  81 */
  82static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
  83{
  84        unsigned long p = bottom & ~31;
  85        mm_segment_t fs;
  86        int i;
  87
  88        /*
  89         * We need to switch to kernel mode so that we can use __get_user
  90         * to safely read from kernel space.  Note that we now dump the
  91         * code first, just in case the backtrace kills us.
  92         */
  93        fs = get_fs();
  94        set_fs(KERNEL_DS);
  95
  96        printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
  97
  98        for (p = bottom & ~31; p < top;) {
  99                printk("%04lx: ", p & 0xffff);
 100
 101                for (i = 0; i < 8; i++, p += 4) {
 102                        unsigned int val;
 103
 104                        if (p < bottom || p >= top)
 105                                printk("         ");
 106                        else {
 107                                __get_user(val, (unsigned long *)p);
 108                                printk("%08x ", val);
 109                        }
 110                }
 111                printk ("\n");
 112        }
 113
 114        set_fs(fs);
 115}
 116
 117static void dump_instr(struct pt_regs *regs)
 118{
 119        unsigned long addr = instruction_pointer(regs);
 120        const int thumb = thumb_mode(regs);
 121        const int width = thumb ? 4 : 8;
 122        mm_segment_t fs;
 123        int i;
 124
 125        /*
 126         * We need to switch to kernel mode so that we can use __get_user
 127         * to safely read from kernel space.  Note that we now dump the
 128         * code first, just in case the backtrace kills us.
 129         */
 130        fs = get_fs();
 131        set_fs(KERNEL_DS);
 132
 133        printk("Code: ");
 134        for (i = -4; i < 1; i++) {
 135                unsigned int val, bad;
 136
 137                if (thumb)
 138                        bad = __get_user(val, &((u16 *)addr)[i]);
 139                else
 140                        bad = __get_user(val, &((u32 *)addr)[i]);
 141
 142                if (!bad)
 143                        printk(i == 0 ? "(%0*x) " : "%0*x ", width, val);
 144                else {
 145                        printk("bad PC value.");
 146                        break;
 147                }
 148        }
 149        printk("\n");
 150
 151        set_fs(fs);
 152}
 153
 154static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 155{
 156        unsigned int fp;
 157        int ok = 1;
 158
 159        printk("Backtrace: ");
 160        fp = regs->ARM_fp;
 161        if (!fp) {
 162                printk("no frame pointer");
 163                ok = 0;
 164        } else if (verify_stack(fp)) {
 165                printk("invalid frame pointer 0x%08x", fp);
 166                ok = 0;
 167        } else if (fp < (unsigned long)(tsk->thread_info + 1))
 168                printk("frame pointer underflow");
 169        printk("\n");
 170
 171        if (ok)
 172                c_backtrace(fp, processor_mode(regs));
 173}
 174
 175void dump_stack(void)
 176{
 177#ifdef CONFIG_DEBUG_ERRORS
 178        __backtrace();
 179#endif
 180}
 181
 182EXPORT_SYMBOL(dump_stack);
 183
 184void show_stack(struct task_struct *tsk, unsigned long *sp)
 185{
 186        unsigned long fp;
 187
 188        if (!tsk)
 189                tsk = current;
 190
 191        if (tsk != current)
 192                fp = thread_saved_fp(tsk);
 193        else
 194                asm("mov%? %0, fp" : "=r" (fp));
 195
 196        c_backtrace(fp, 0x10);
 197        barrier();
 198}
 199
 200DEFINE_SPINLOCK(die_lock);
 201
 202/*
 203 * This function is protected against re-entrancy.
 204 */
 205NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
 206{
 207        struct task_struct *tsk = current;
 208        static int die_counter;
 209
 210        console_verbose();
 211        spin_lock_irq(&die_lock);
 212        bust_spinlocks(1);
 213
 214        printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);
 215        print_modules();
 216        __show_regs(regs);
 217        printk("Process %s (pid: %d, stack limit = 0x%p)\n",
 218                tsk->comm, tsk->pid, tsk->thread_info + 1);
 219
 220        if (!user_mode(regs) || in_interrupt()) {
 221                dump_mem("Stack: ", regs->ARM_sp,
 222                         THREAD_SIZE + (unsigned long)tsk->thread_info);
 223                dump_backtrace(regs, tsk);
 224                dump_instr(regs);
 225        }
 226
 227        bust_spinlocks(0);
 228        spin_unlock_irq(&die_lock);
 229        do_exit(SIGSEGV);
 230}
 231
 232void die_if_kernel(const char *str, struct pt_regs *regs, int err)
 233{
 234        if (user_mode(regs))
 235                return;
 236
 237        die(str, regs, err);
 238}
 239
 240static void notify_die(const char *str, struct pt_regs *regs, siginfo_t *info,
 241                       unsigned long err, unsigned long trap)
 242{
 243        if (user_mode(regs)) {
 244                current->thread.error_code = err;
 245                current->thread.trap_no = trap;
 246
 247                force_sig_info(info->si_signo, info, current);
 248        } else {
 249                die(str, regs, err);
 250        }
 251}
 252
 253static LIST_HEAD(undef_hook);
 254static DEFINE_SPINLOCK(undef_lock);
 255
 256void register_undef_hook(struct undef_hook *hook)
 257{
 258        spin_lock_irq(&undef_lock);
 259        list_add(&hook->node, &undef_hook);
 260        spin_unlock_irq(&undef_lock);
 261}
 262
 263void unregister_undef_hook(struct undef_hook *hook)
 264{
 265        spin_lock_irq(&undef_lock);
 266        list_del(&hook->node);
 267        spin_unlock_irq(&undef_lock);
 268}
 269
 270asmlinkage void do_undefinstr(struct pt_regs *regs)
 271{
 272        unsigned int correction = thumb_mode(regs) ? 2 : 4;
 273        unsigned int instr;
 274        struct undef_hook *hook;
 275        siginfo_t info;
 276        void __user *pc;
 277
 278        /*
 279         * According to the ARM ARM, PC is 2 or 4 bytes ahead,
 280         * depending whether we're in Thumb mode or not.
 281         * Correct this offset.
 282         */
 283        regs->ARM_pc -= correction;
 284
 285        pc = (void __user *)instruction_pointer(regs);
 286        if (thumb_mode(regs)) {
 287                get_user(instr, (u16 __user *)pc);
 288        } else {
 289                get_user(instr, (u32 __user *)pc);
 290        }
 291
 292        spin_lock_irq(&undef_lock);
 293        list_for_each_entry(hook, &undef_hook, node) {
 294                if ((instr & hook->instr_mask) == hook->instr_val &&
 295                    (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
 296                        if (hook->fn(regs, instr) == 0) {
 297                                spin_unlock_irq(&undef_lock);
 298                                return;
 299                        }
 300                }
 301        }
 302        spin_unlock_irq(&undef_lock);
 303
 304#ifdef CONFIG_DEBUG_USER
 305        if (user_debug & UDBG_UNDEFINED) {
 306                printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
 307                        current->comm, current->pid, pc);
 308                dump_instr(regs);
 309        }
 310#endif
 311
 312        info.si_signo = SIGILL;
 313        info.si_errno = 0;
 314        info.si_code  = ILL_ILLOPC;
 315        info.si_addr  = pc;
 316
 317        notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 318}
 319
 320asmlinkage void do_unexp_fiq (struct pt_regs *regs)
 321{
 322#ifndef CONFIG_IGNORE_FIQ
 323        printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
 324        printk("You may have a hardware problem...\n");
 325#endif
 326}
 327
 328/*
 329 * bad_mode handles the impossible case in the vectors.  If you see one of
 330 * these, then it's extremely serious, and could mean you have buggy hardware.
 331 * It never returns, and never tries to sync.  We hope that we can at least
 332 * dump out some state information...
 333 */
 334asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
 335{
 336        console_verbose();
 337
 338        printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
 339                handler[reason], processor_modes[proc_mode]);
 340
 341        die("Oops - bad mode", regs, 0);
 342        local_irq_disable();
 343        panic("bad mode");
 344}
 345
 346static int bad_syscall(int n, struct pt_regs *regs)
 347{
 348        struct thread_info *thread = current_thread_info();
 349        siginfo_t info;
 350
 351        if (current->personality != PER_LINUX && thread->exec_domain->handler) {
 352                thread->exec_domain->handler(n, regs);
 353                return regs->ARM_r0;
 354        }
 355
 356#ifdef CONFIG_DEBUG_USER
 357        if (user_debug & UDBG_SYSCALL) {
 358                printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
 359                        current->pid, current->comm, n);
 360                dump_instr(regs);
 361        }
 362#endif
 363
 364        info.si_signo = SIGILL;
 365        info.si_errno = 0;
 366        info.si_code  = ILL_ILLTRP;
 367        info.si_addr  = (void __user *)instruction_pointer(regs) -
 368                         (thumb_mode(regs) ? 2 : 4);
 369
 370        notify_die("Oops - bad syscall", regs, &info, n, 0);
 371
 372        return regs->ARM_r0;
 373}
 374
 375static inline void
 376do_cache_op(unsigned long start, unsigned long end, int flags)
 377{
 378        struct vm_area_struct *vma;
 379
 380        if (end < start || flags)
 381                return;
 382
 383        vma = find_vma(current->active_mm, start);
 384        if (vma && vma->vm_start < end) {
 385                if (start < vma->vm_start)
 386                        start = vma->vm_start;
 387                if (end > vma->vm_end)
 388                        end = vma->vm_end;
 389
 390                flush_cache_user_range(vma, start, end);
 391        }
 392}
 393
 394/*
 395 * Handle all unrecognised system calls.
 396 *  0x9f0000 - 0x9fffff are some more esoteric system calls
 397 */
 398#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
 399asmlinkage int arm_syscall(int no, struct pt_regs *regs)
 400{
 401        struct thread_info *thread = current_thread_info();
 402        siginfo_t info;
 403
 404        if ((no >> 16) != 0x9f)
 405                return bad_syscall(no, regs);
 406
 407        switch (no & 0xffff) {
 408        case 0: /* branch through 0 */
 409                info.si_signo = SIGSEGV;
 410                info.si_errno = 0;
 411                info.si_code  = SEGV_MAPERR;
 412                info.si_addr  = NULL;
 413
 414                notify_die("branch through zero", regs, &info, 0, 0);
 415                return 0;
 416
 417        case NR(breakpoint): /* SWI BREAK_POINT */
 418                regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
 419                ptrace_break(current, regs);
 420                return regs->ARM_r0;
 421
 422        /*
 423         * Flush a region from virtual address 'r0' to virtual address 'r1'
 424         * _exclusive_.  There is no alignment requirement on either address;
 425         * user space does not need to know the hardware cache layout.
 426         *
 427         * r2 contains flags.  It should ALWAYS be passed as ZERO until it
 428         * is defined to be something else.  For now we ignore it, but may
 429         * the fires of hell burn in your belly if you break this rule. ;)
 430         *
 431         * (at a later date, we may want to allow this call to not flush
 432         * various aspects of the cache.  Passing '0' will guarantee that
 433         * everything necessary gets flushed to maintain consistency in
 434         * the specified region).
 435         */
 436        case NR(cacheflush):
 437                do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);
 438                return 0;
 439
 440        case NR(usr26):
 441                if (!(elf_hwcap & HWCAP_26BIT))
 442                        break;
 443                regs->ARM_cpsr &= ~MODE32_BIT;
 444                return regs->ARM_r0;
 445
 446        case NR(usr32):
 447                if (!(elf_hwcap & HWCAP_26BIT))
 448                        break;
 449                regs->ARM_cpsr |= MODE32_BIT;
 450                return regs->ARM_r0;
 451
 452        case NR(set_tls):
 453                thread->tp_value = regs->ARM_r0;
 454#if defined(CONFIG_HAS_TLS_REG)
 455                asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
 456#elif !defined(CONFIG_TLS_REG_EMUL)
 457                /*
 458                 * User space must never try to access this directly.
 459                 * Expect your app to break eventually if you do so.
 460                 * The user helper at 0xffff0fe0 must be used instead.
 461                 * (see entry-armv.S for details)
 462                 */
 463                *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
 464#endif
 465                return 0;
 466
 467#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG
 468        /*
 469         * Atomically store r1 in *r2 if *r2 is equal to r0 for user space.
 470         * Return zero in r0 if *MEM was changed or non-zero if no exchange
 471         * happened.  Also set the user C flag accordingly.
 472         * If access permissions have to be fixed up then non-zero is
 473         * returned and the operation has to be re-attempted.
 474         *
 475         * *NOTE*: This is a ghost syscall private to the kernel.  Only the
 476         * __kuser_cmpxchg code in entry-armv.S should be aware of its
 477         * existence.  Don't ever use this from user code.
 478         */
 479        case 0xfff0:
 480        {
 481                extern void do_DataAbort(unsigned long addr, unsigned int fsr,
 482                                         struct pt_regs *regs);
 483                unsigned long val;
 484                unsigned long addr = regs->ARM_r2;
 485                struct mm_struct *mm = current->mm;
 486                pgd_t *pgd; pmd_t *pmd; pte_t *pte;
 487
 488                regs->ARM_cpsr &= ~PSR_C_BIT;
 489                spin_lock(&mm->page_table_lock);
 490                pgd = pgd_offset(mm, addr);
 491                if (!pgd_present(*pgd))
 492                        goto bad_access;
 493                pmd = pmd_offset(pgd, addr);
 494                if (!pmd_present(*pmd))
 495                        goto bad_access;
 496                pte = pte_offset_map(pmd, addr);
 497                if (!pte_present(*pte) || !pte_write(*pte))
 498                        goto bad_access;
 499                val = *(unsigned long *)addr;
 500                val -= regs->ARM_r0;
 501                if (val == 0) {
 502                        *(unsigned long *)addr = regs->ARM_r1;
 503                        regs->ARM_cpsr |= PSR_C_BIT;
 504                }
 505                spin_unlock(&mm->page_table_lock);
 506                return val;
 507
 508                bad_access:
 509                spin_unlock(&mm->page_table_lock);
 510                /* simulate a read access fault */
 511                do_DataAbort(addr, 15 + (1 << 11), regs);
 512                return -1;
 513        }
 514#endif
 515
 516        default:
 517                /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
 518                   if not implemented, rather than raising SIGILL.  This
 519                   way the calling program can gracefully determine whether
 520                   a feature is supported.  */
 521                if (no <= 0x7ff)
 522                        return -ENOSYS;
 523                break;
 524        }
 525#ifdef CONFIG_DEBUG_USER
 526        /*
 527         * experience shows that these seem to indicate that
 528         * something catastrophic has happened
 529         */
 530        if (user_debug & UDBG_SYSCALL) {
 531                printk("[%d] %s: arm syscall %d\n",
 532                       current->pid, current->comm, no);
 533                dump_instr(regs);
 534                if (user_mode(regs)) {
 535                        __show_regs(regs);
 536                        c_backtrace(regs->ARM_fp, processor_mode(regs));
 537                }
 538        }
 539#endif
 540        info.si_signo = SIGILL;
 541        info.si_errno = 0;
 542        info.si_code  = ILL_ILLTRP;
 543        info.si_addr  = (void __user *)instruction_pointer(regs) -
 544                         (thumb_mode(regs) ? 2 : 4);
 545
 546        notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
 547        return 0;
 548}
 549
 550#ifdef CONFIG_TLS_REG_EMUL
 551
 552/*
 553 * We might be running on an ARMv6+ processor which should have the TLS
 554 * register but for some reason we can't use it, or maybe an SMP system
 555 * using a pre-ARMv6 processor (there are apparently a few prototypes like
 556 * that in existence) and therefore access to that register must be
 557 * emulated.
 558 */
 559
 560static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
 561{
 562        int reg = (instr >> 12) & 15;
 563        if (reg == 15)
 564                return 1;
 565        regs->uregs[reg] = current_thread_info()->tp_value;
 566        regs->ARM_pc += 4;
 567        return 0;
 568}
 569
 570static struct undef_hook arm_mrc_hook = {
 571        .instr_mask     = 0x0fff0fff,
 572        .instr_val      = 0x0e1d0f70,
 573        .cpsr_mask      = PSR_T_BIT,
 574        .cpsr_val       = 0,
 575        .fn             = get_tp_trap,
 576};
 577
 578static int __init arm_mrc_hook_init(void)
 579{
 580        register_undef_hook(&arm_mrc_hook);
 581        return 0;
 582}
 583
 584late_initcall(arm_mrc_hook_init);
 585
 586#endif
 587
 588void __bad_xchg(volatile void *ptr, int size)
 589{
 590        printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
 591                __builtin_return_address(0), ptr, size);
 592        BUG();
 593}
 594EXPORT_SYMBOL(__bad_xchg);
 595
 596/*
 597 * A data abort trap was taken, but we did not handle the instruction.
 598 * Try to abort the user program, or panic if it was the kernel.
 599 */
 600asmlinkage void
 601baddataabort(int code, unsigned long instr, struct pt_regs *regs)
 602{
 603        unsigned long addr = instruction_pointer(regs);
 604        siginfo_t info;
 605
 606#ifdef CONFIG_DEBUG_USER
 607        if (user_debug & UDBG_BADABORT) {
 608                printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
 609                        current->pid, current->comm, code, instr);
 610                dump_instr(regs);
 611                show_pte(current->mm, addr);
 612        }
 613#endif
 614
 615        info.si_signo = SIGILL;
 616        info.si_errno = 0;
 617        info.si_code  = ILL_ILLOPC;
 618        info.si_addr  = (void __user *)addr;
 619
 620        notify_die("unknown data abort code", regs, &info, instr, 0);
 621}
 622
 623volatile void __bug(const char *file, int line, void *data)
 624{
 625        printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
 626        if (data)
 627                printk(" - extra data = %p", data);
 628        printk("\n");
 629        *(int *)0 = 0;
 630}
 631EXPORT_SYMBOL(__bug);
 632
 633void __readwrite_bug(const char *fn)
 634{
 635        printk("%s called, but not implemented\n", fn);
 636        BUG();
 637}
 638EXPORT_SYMBOL(__readwrite_bug);
 639
 640void __pte_error(const char *file, int line, unsigned long val)
 641{
 642        printk("%s:%d: bad pte %08lx.\n", file, line, val);
 643}
 644
 645void __pmd_error(const char *file, int line, unsigned long val)
 646{
 647        printk("%s:%d: bad pmd %08lx.\n", file, line, val);
 648}
 649
 650void __pgd_error(const char *file, int line, unsigned long val)
 651{
 652        printk("%s:%d: bad pgd %08lx.\n", file, line, val);
 653}
 654
 655asmlinkage void __div0(void)
 656{
 657        printk("Division by zero in kernel.\n");
 658        dump_stack();
 659}
 660EXPORT_SYMBOL(__div0);
 661
 662void abort(void)
 663{
 664        BUG();
 665
 666        /* if that doesn't kill us, halt */
 667        panic("Oops failed to kill thread");
 668}
 669EXPORT_SYMBOL(abort);
 670
 671void __init trap_init(void)
 672{
 673        extern char __stubs_start[], __stubs_end[];
 674        extern char __vectors_start[], __vectors_end[];
 675        extern char __kuser_helper_start[], __kuser_helper_end[];
 676        int kuser_sz = __kuser_helper_end - __kuser_helper_start;
 677
 678        /*
 679         * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
 680         * into the vector page, mapped at 0xffff0000, and ensure these
 681         * are visible to the instruction stream.
 682         */
 683        memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);
 684        memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);
 685        memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz);
 686        flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE);
 687        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 688}
 689
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.