linux/arch/sparc64/kernel/sys_sparc.c
<<
>>
Prefs
   1/* linux/arch/sparc64/kernel/sys_sparc.c
   2 *
   3 * This file contains various random system calls that
   4 * have a non-standard calling sequence on the Linux/sparc
   5 * platform.
   6 */
   7
   8#include <linux/errno.h>
   9#include <linux/types.h>
  10#include <linux/sched.h>
  11#include <linux/fs.h>
  12#include <linux/file.h>
  13#include <linux/mm.h>
  14#include <linux/sem.h>
  15#include <linux/msg.h>
  16#include <linux/shm.h>
  17#include <linux/stat.h>
  18#include <linux/mman.h>
  19#include <linux/utsname.h>
  20#include <linux/smp.h>
  21#include <linux/slab.h>
  22#include <linux/syscalls.h>
  23#include <linux/ipc.h>
  24#include <linux/personality.h>
  25#include <linux/random.h>
  26
  27#include <asm/uaccess.h>
  28#include <asm/utrap.h>
  29#include <asm/perfctr.h>
  30#include <asm/unistd.h>
  31
  32#include "entry.h"
  33#include "systbls.h"
  34
  35/* #define DEBUG_UNIMP_SYSCALL */
  36
  37asmlinkage unsigned long sys_getpagesize(void)
  38{
  39        return PAGE_SIZE;
  40}
  41
  42#define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL))
  43#define VA_EXCLUDE_END   (0xfffff80000000000UL + (1UL << 32UL))
  44
  45/* Does addr --> addr+len fall within 4GB of the VA-space hole or
  46 * overflow past the end of the 64-bit address space?
  47 */
  48static inline int invalid_64bit_range(unsigned long addr, unsigned long len)
  49{
  50        unsigned long va_exclude_start, va_exclude_end;
  51
  52        va_exclude_start = VA_EXCLUDE_START;
  53        va_exclude_end   = VA_EXCLUDE_END;
  54
  55        if (unlikely(len >= va_exclude_start))
  56                return 1;
  57
  58        if (unlikely((addr + len) < addr))
  59                return 1;
  60
  61        if (unlikely((addr >= va_exclude_start && addr < va_exclude_end) ||
  62                     ((addr + len) >= va_exclude_start &&
  63                      (addr + len) < va_exclude_end)))
  64                return 1;
  65
  66        return 0;
  67}
  68
  69/* Does start,end straddle the VA-space hole?  */
  70static inline int straddles_64bit_va_hole(unsigned long start, unsigned long end)
  71{
  72        unsigned long va_exclude_start, va_exclude_end;
  73
  74        va_exclude_start = VA_EXCLUDE_START;
  75        va_exclude_end   = VA_EXCLUDE_END;
  76
  77        if (likely(start < va_exclude_start && end < va_exclude_start))
  78                return 0;
  79
  80        if (likely(start >= va_exclude_end && end >= va_exclude_end))
  81                return 0;
  82
  83        return 1;
  84}
  85
  86/* These functions differ from the default implementations in
  87 * mm/mmap.c in two ways:
  88 *
  89 * 1) For file backed MAP_SHARED mmap()'s we D-cache color align,
  90 *    for fixed such mappings we just validate what the user gave us.
  91 * 2) For 64-bit tasks we avoid mapping anything within 4GB of
  92 *    the spitfire/niagara VA-hole.
  93 */
  94
  95static inline unsigned long COLOUR_ALIGN(unsigned long addr,
  96                                         unsigned long pgoff)
  97{
  98        unsigned long base = (addr+SHMLBA-1)&~(SHMLBA-1);
  99        unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1);
 100
 101        return base + off;
 102}
 103
 104static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
 105                                              unsigned long pgoff)
 106{
 107        unsigned long base = addr & ~(SHMLBA-1);
 108        unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1);
 109
 110        if (base + off <= addr)
 111                return base + off;
 112        return base - off;
 113}
 114
 115unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 116{
 117        struct mm_struct *mm = current->mm;
 118        struct vm_area_struct * vma;
 119        unsigned long task_size = TASK_SIZE;
 120        unsigned long start_addr;
 121        int do_color_align;
 122
 123        if (flags & MAP_FIXED) {
 124                /* We do not accept a shared mapping if it would violate
 125                 * cache aliasing constraints.
 126                 */
 127                if ((flags & MAP_SHARED) &&
 128                    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
 129                        return -EINVAL;
 130                return addr;
 131        }
 132
 133        if (test_thread_flag(TIF_32BIT))
 134                task_size = STACK_TOP32;
 135        if (unlikely(len > task_size || len >= VA_EXCLUDE_START))
 136                return -ENOMEM;
 137
 138        do_color_align = 0;
 139        if (filp || (flags & MAP_SHARED))
 140                do_color_align = 1;
 141
 142        if (addr) {
 143                if (do_color_align)
 144                        addr = COLOUR_ALIGN(addr, pgoff);
 145                else
 146                        addr = PAGE_ALIGN(addr);
 147
 148                vma = find_vma(mm, addr);
 149                if (task_size - len >= addr &&
 150                    (!vma || addr + len <= vma->vm_start))
 151                        return addr;
 152        }
 153
 154        if (len > mm->cached_hole_size) {
 155                start_addr = addr = mm->free_area_cache;
 156        } else {
 157                start_addr = addr = TASK_UNMAPPED_BASE;
 158                mm->cached_hole_size = 0;
 159        }
 160
 161        task_size -= len;
 162
 163full_search:
 164        if (do_color_align)
 165                addr = COLOUR_ALIGN(addr, pgoff);
 166        else
 167                addr = PAGE_ALIGN(addr);
 168
 169        for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
 170                /* At this point:  (!vma || addr < vma->vm_end). */
 171                if (addr < VA_EXCLUDE_START &&
 172                    (addr + len) >= VA_EXCLUDE_START) {
 173                        addr = VA_EXCLUDE_END;
 174                        vma = find_vma(mm, VA_EXCLUDE_END);
 175                }
 176                if (unlikely(task_size < addr)) {
 177                        if (start_addr != TASK_UNMAPPED_BASE) {
 178                                start_addr = addr = TASK_UNMAPPED_BASE;
 179                                mm->cached_hole_size = 0;
 180                                goto full_search;
 181                        }
 182                        return -ENOMEM;
 183                }
 184                if (likely(!vma || addr + len <= vma->vm_start)) {
 185                        /*
 186                         * Remember the place where we stopped the search:
 187                         */
 188                        mm->free_area_cache = addr + len;
 189                        return addr;
 190                }
 191                if (addr + mm->cached_hole_size < vma->vm_start)
 192                        mm->cached_hole_size = vma->vm_start - addr;
 193
 194                addr = vma->vm_end;
 195                if (do_color_align)
 196                        addr = COLOUR_ALIGN(addr, pgoff);
 197        }
 198}
 199
 200unsigned long
 201arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 202                          const unsigned long len, const unsigned long pgoff,
 203                          const unsigned long flags)
 204{
 205        struct vm_area_struct *vma;
 206        struct mm_struct *mm = current->mm;
 207        unsigned long task_size = STACK_TOP32;
 208        unsigned long addr = addr0;
 209        int do_color_align;
 210
 211        /* This should only ever run for 32-bit processes.  */
 212        BUG_ON(!test_thread_flag(TIF_32BIT));
 213
 214        if (flags & MAP_FIXED) {
 215                /* We do not accept a shared mapping if it would violate
 216                 * cache aliasing constraints.
 217                 */
 218                if ((flags & MAP_SHARED) &&
 219                    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
 220                        return -EINVAL;
 221                return addr;
 222        }
 223
 224        if (unlikely(len > task_size))
 225                return -ENOMEM;
 226
 227        do_color_align = 0;
 228        if (filp || (flags & MAP_SHARED))
 229                do_color_align = 1;
 230
 231        /* requesting a specific address */
 232        if (addr) {
 233                if (do_color_align)
 234                        addr = COLOUR_ALIGN(addr, pgoff);
 235                else
 236                        addr = PAGE_ALIGN(addr);
 237
 238                vma = find_vma(mm, addr);
 239                if (task_size - len >= addr &&
 240                    (!vma || addr + len <= vma->vm_start))
 241                        return addr;
 242        }
 243
 244        /* check if free_area_cache is useful for us */
 245        if (len <= mm->cached_hole_size) {
 246                mm->cached_hole_size = 0;
 247                mm->free_area_cache = mm->mmap_base;
 248        }
 249
 250        /* either no address requested or can't fit in requested address hole */
 251        addr = mm->free_area_cache;
 252        if (do_color_align) {
 253                unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff);
 254
 255                addr = base + len;
 256        }
 257
 258        /* make sure it can fit in the remaining address space */
 259        if (likely(addr > len)) {
 260                vma = find_vma(mm, addr-len);
 261                if (!vma || addr <= vma->vm_start) {
 262                        /* remember the address as a hint for next time */
 263                        return (mm->free_area_cache = addr-len);
 264                }
 265        }
 266
 267        if (unlikely(mm->mmap_base < len))
 268                goto bottomup;
 269
 270        addr = mm->mmap_base-len;
 271        if (do_color_align)
 272                addr = COLOUR_ALIGN_DOWN(addr, pgoff);
 273
 274        do {
 275                /*
 276                 * Lookup failure means no vma is above this address,
 277                 * else if new region fits below vma->vm_start,
 278                 * return with success:
 279                 */
 280                vma = find_vma(mm, addr);
 281                if (likely(!vma || addr+len <= vma->vm_start)) {
 282                        /* remember the address as a hint for next time */
 283                        return (mm->free_area_cache = addr);
 284                }
 285
 286                /* remember the largest hole we saw so far */
 287                if (addr + mm->cached_hole_size < vma->vm_start)
 288                        mm->cached_hole_size = vma->vm_start - addr;
 289
 290                /* try just below the current vma->vm_start */
 291                addr = vma->vm_start-len;
 292                if (do_color_align)
 293                        addr = COLOUR_ALIGN_DOWN(addr, pgoff);
 294        } while (likely(len < vma->vm_start));
 295
 296bottomup:
 297        /*
 298         * A failed mmap() very likely causes application failure,
 299         * so fall back to the bottom-up function here. This scenario
 300         * can happen with large stack limits and large mmap()
 301         * allocations.
 302         */
 303        mm->cached_hole_size = ~0UL;
 304        mm->free_area_cache = TASK_UNMAPPED_BASE;
 305        addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
 306        /*
 307         * Restore the topdown base:
 308         */
 309        mm->free_area_cache = mm->mmap_base;
 310        mm->cached_hole_size = ~0UL;
 311
 312        return addr;
 313}
 314
 315/* Try to align mapping such that we align it as much as possible. */
 316unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 317{
 318        unsigned long align_goal, addr = -ENOMEM;
 319
 320        if (flags & MAP_FIXED) {
 321                /* Ok, don't mess with it. */
 322                return get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
 323        }
 324        flags &= ~MAP_SHARED;
 325
 326        align_goal = PAGE_SIZE;
 327        if (len >= (4UL * 1024 * 1024))
 328                align_goal = (4UL * 1024 * 1024);
 329        else if (len >= (512UL * 1024))
 330                align_goal = (512UL * 1024);
 331        else if (len >= (64UL * 1024))
 332                align_goal = (64UL * 1024);
 333
 334        do {
 335                addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags);
 336                if (!(addr & ~PAGE_MASK)) {
 337                        addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL);
 338                        break;
 339                }
 340
 341                if (align_goal == (4UL * 1024 * 1024))
 342                        align_goal = (512UL * 1024);
 343                else if (align_goal == (512UL * 1024))
 344                        align_goal = (64UL * 1024);
 345                else
 346                        align_goal = PAGE_SIZE;
 347        } while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE);
 348
 349        /* Mapping is smaller than 64K or larger areas could not
 350         * be obtained.
 351         */
 352        if (addr & ~PAGE_MASK)
 353                addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
 354
 355        return addr;
 356}
 357
 358/* Essentially the same as PowerPC... */
 359void arch_pick_mmap_layout(struct mm_struct *mm)
 360{
 361        unsigned long random_factor = 0UL;
 362
 363        if (current->flags & PF_RANDOMIZE) {
 364                random_factor = get_random_int();
 365                if (test_thread_flag(TIF_32BIT))
 366                        random_factor &= ((1 * 1024 * 1024) - 1);
 367                else
 368                        random_factor = ((random_factor << PAGE_SHIFT) &
 369                                         0xffffffffUL);
 370        }
 371
 372        /*
 373         * Fall back to the standard layout if the personality
 374         * bit is set, or if the expected stack growth is unlimited:
 375         */
 376        if (!test_thread_flag(TIF_32BIT) ||
 377            (current->personality & ADDR_COMPAT_LAYOUT) ||
 378            current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY ||
 379            sysctl_legacy_va_layout) {
 380                mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
 381                mm->get_unmapped_area = arch_get_unmapped_area;
 382                mm->unmap_area = arch_unmap_area;
 383        } else {
 384                /* We know it's 32-bit */
 385                unsigned long task_size = STACK_TOP32;
 386                unsigned long gap;
 387
 388                gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
 389                if (gap < 128 * 1024 * 1024)
 390                        gap = 128 * 1024 * 1024;
 391                if (gap > (task_size / 6 * 5))
 392                        gap = (task_size / 6 * 5);
 393
 394                mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor);
 395                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
 396                mm->unmap_area = arch_unmap_area_topdown;
 397        }
 398}
 399
 400asmlinkage unsigned long sparc_brk(unsigned long brk)
 401{
 402        /* People could try to be nasty and use ta 0x6d in 32bit programs */
 403        if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32)
 404                return current->mm->brk;
 405
 406        if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk)))
 407                return current->mm->brk;
 408
 409        return sys_brk(brk);
 410}
 411                                                                
 412/*
 413 * sys_pipe() is the normal C calling standard for creating
 414 * a pipe. It's not the way unix traditionally does this, though.
 415 */
 416asmlinkage long sparc_pipe(struct pt_regs *regs)
 417{
 418        int fd[2];
 419        int error;
 420
 421        error = do_pipe(fd);
 422        if (error)
 423                goto out;
 424        regs->u_regs[UREG_I1] = fd[1];
 425        error = fd[0];
 426out:
 427        return error;
 428}
 429
 430/*
 431 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
 432 *
 433 * This is really horribly ugly.
 434 */
 435
 436asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
 437                        unsigned long third, void __user *ptr, long fifth)
 438{
 439        long err;
 440
 441        /* No need for backward compatibility. We can start fresh... */
 442        if (call <= SEMCTL) {
 443                switch (call) {
 444                case SEMOP:
 445                        err = sys_semtimedop(first, ptr,
 446                                             (unsigned)second, NULL);
 447                        goto out;
 448                case SEMTIMEDOP:
 449                        err = sys_semtimedop(first, ptr, (unsigned)second,
 450                                (const struct timespec __user *)
 451                                             (unsigned long) fifth);
 452                        goto out;
 453                case SEMGET:
 454                        err = sys_semget(first, (int)second, (int)third);
 455                        goto out;
 456                case SEMCTL: {
 457                        err = sys_semctl(first, second,
 458                                         (int)third | IPC_64,
 459                                         (union semun) ptr);
 460                        goto out;
 461                }
 462                default:
 463                        err = -ENOSYS;
 464                        goto out;
 465                };
 466        }
 467        if (call <= MSGCTL) {
 468                switch (call) {
 469                case MSGSND:
 470                        err = sys_msgsnd(first, ptr, (size_t)second,
 471                                         (int)third);
 472                        goto out;
 473                case MSGRCV:
 474                        err = sys_msgrcv(first, ptr, (size_t)second, fifth,
 475                                         (int)third);
 476                        goto out;
 477                case MSGGET:
 478                        err = sys_msgget((key_t)first, (int)second);
 479                        goto out;
 480                case MSGCTL:
 481                        err = sys_msgctl(first, (int)second | IPC_64, ptr);
 482                        goto out;
 483                default:
 484                        err = -ENOSYS;
 485                        goto out;
 486                };
 487        }
 488        if (call <= SHMCTL) {
 489                switch (call) {
 490                case SHMAT: {
 491                        ulong raddr;
 492                        err = do_shmat(first, ptr, (int)second, &raddr);
 493                        if (!err) {
 494                                if (put_user(raddr,
 495                                             (ulong __user *) third))
 496                                        err = -EFAULT;
 497                        }
 498                        goto out;
 499                }
 500                case SHMDT:
 501                        err = sys_shmdt(ptr);
 502                        goto out;
 503                case SHMGET:
 504                        err = sys_shmget(first, (size_t)second, (int)third);
 505                        goto out;
 506                case SHMCTL:
 507                        err = sys_shmctl(first, (int)second | IPC_64, ptr);
 508                        goto out;
 509                default:
 510                        err = -ENOSYS;
 511                        goto out;
 512                };
 513        } else {
 514                err = -ENOSYS;
 515        }
 516out:
 517        return err;
 518}
 519
 520asmlinkage long sparc64_newuname(struct new_utsname __user *name)
 521{
 522        int ret = sys_newuname(name);
 523        
 524        if (current->personality == PER_LINUX32 && !ret) {
 525                ret = (copy_to_user(name->machine, "sparc\0\0", 8)
 526                       ? -EFAULT : 0);
 527        }
 528        return ret;
 529}
 530
 531asmlinkage long sparc64_personality(unsigned long personality)
 532{
 533        int ret;
 534
 535        if (current->personality == PER_LINUX32 &&
 536            personality == PER_LINUX)
 537                personality = PER_LINUX32;
 538        ret = sys_personality(personality);
 539        if (ret == PER_LINUX32)
 540                ret = PER_LINUX;
 541
 542        return ret;
 543}
 544
 545int sparc64_mmap_check(unsigned long addr, unsigned long len)
 546{
 547        if (test_thread_flag(TIF_32BIT)) {
 548                if (len >= STACK_TOP32)
 549                        return -EINVAL;
 550
 551                if (addr > STACK_TOP32 - len)
 552                        return -EINVAL;
 553        } else {
 554                if (len >= VA_EXCLUDE_START)
 555                        return -EINVAL;
 556
 557                if (invalid_64bit_range(addr, len))
 558                        return -EINVAL;
 559        }
 560
 561        return 0;
 562}
 563
 564/* Linux version of mmap */
 565asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
 566        unsigned long prot, unsigned long flags, unsigned long fd,
 567        unsigned long off)
 568{
 569        struct file * file = NULL;
 570        unsigned long retval = -EBADF;
 571
 572        if (!(flags & MAP_ANONYMOUS)) {
 573                file = fget(fd);
 574                if (!file)
 575                        goto out;
 576        }
 577        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 578        len = PAGE_ALIGN(len);
 579
 580        down_write(&current->mm->mmap_sem);
 581        retval = do_mmap(file, addr, len, prot, flags, off);
 582        up_write(&current->mm->mmap_sem);
 583
 584        if (file)
 585                fput(file);
 586out:
 587        return retval;
 588}
 589
 590asmlinkage long sys64_munmap(unsigned long addr, size_t len)
 591{
 592        long ret;
 593
 594        if (invalid_64bit_range(addr, len))
 595                return -EINVAL;
 596
 597        down_write(&current->mm->mmap_sem);
 598        ret = do_munmap(current->mm, addr, len);
 599        up_write(&current->mm->mmap_sem);
 600        return ret;
 601}
 602
 603extern unsigned long do_mremap(unsigned long addr,
 604        unsigned long old_len, unsigned long new_len,
 605        unsigned long flags, unsigned long new_addr);
 606                
 607asmlinkage unsigned long sys64_mremap(unsigned long addr,
 608        unsigned long old_len, unsigned long new_len,
 609        unsigned long flags, unsigned long new_addr)
 610{
 611        unsigned long ret = -EINVAL;
 612
 613        if (test_thread_flag(TIF_32BIT))
 614                goto out;
 615        if (unlikely(new_len >= VA_EXCLUDE_START))
 616                goto out;
 617        if (unlikely(sparc64_mmap_check(addr, old_len)))
 618                goto out;
 619        if (unlikely(sparc64_mmap_check(new_addr, new_len)))
 620                goto out;
 621
 622        down_write(&current->mm->mmap_sem);
 623        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 624        up_write(&current->mm->mmap_sem);
 625out:
 626        return ret;       
 627}
 628
 629/* we come to here via sys_nis_syscall so it can setup the regs argument */
 630asmlinkage unsigned long c_sys_nis_syscall(struct pt_regs *regs)
 631{
 632        static int count;
 633        
 634        /* Don't make the system unusable, if someone goes stuck */
 635        if (count++ > 5)
 636                return -ENOSYS;
 637
 638        printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
 639#ifdef DEBUG_UNIMP_SYSCALL      
 640        show_regs (regs);
 641#endif
 642
 643        return -ENOSYS;
 644}
 645
 646/* #define DEBUG_SPARC_BREAKPOINT */
 647
 648asmlinkage void sparc_breakpoint(struct pt_regs *regs)
 649{
 650        siginfo_t info;
 651
 652        if (test_thread_flag(TIF_32BIT)) {
 653                regs->tpc &= 0xffffffff;
 654                regs->tnpc &= 0xffffffff;
 655        }
 656#ifdef DEBUG_SPARC_BREAKPOINT
 657        printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
 658#endif
 659        info.si_signo = SIGTRAP;
 660        info.si_errno = 0;
 661        info.si_code = TRAP_BRKPT;
 662        info.si_addr = (void __user *)regs->tpc;
 663        info.si_trapno = 0;
 664        force_sig_info(SIGTRAP, &info, current);
 665#ifdef DEBUG_SPARC_BREAKPOINT
 666        printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
 667#endif
 668}
 669
 670extern void check_pending(int signum);
 671
 672asmlinkage long sys_getdomainname(char __user *name, int len)
 673{
 674        int nlen, err;
 675
 676        if (len < 0)
 677                return -EINVAL;
 678
 679        down_read(&uts_sem);
 680        
 681        nlen = strlen(utsname()->domainname) + 1;
 682        err = -EINVAL;
 683        if (nlen > len)
 684                goto out;
 685
 686        err = -EFAULT;
 687        if (!copy_to_user(name, utsname()->domainname, nlen))
 688                err = 0;
 689
 690out:
 691        up_read(&uts_sem);
 692        return err;
 693}
 694
 695asmlinkage long solaris_syscall(struct pt_regs *regs)
 696{
 697        static int count;
 698
 699        regs->tpc = regs->tnpc;
 700        regs->tnpc += 4;
 701        if (test_thread_flag(TIF_32BIT)) {
 702                regs->tpc &= 0xffffffff;
 703                regs->tnpc &= 0xffffffff;
 704        }
 705        if (++count <= 5) {
 706                printk ("For Solaris binary emulation you need solaris module loaded\n");
 707                show_regs (regs);
 708        }
 709        send_sig(SIGSEGV, current, 1);
 710
 711        return -ENOSYS;
 712}
 713
 714#ifndef CONFIG_SUNOS_EMUL
 715asmlinkage long sunos_syscall(struct pt_regs *regs)
 716{
 717        static int count;
 718
 719        regs->tpc = regs->tnpc;
 720        regs->tnpc += 4;
 721        if (test_thread_flag(TIF_32BIT)) {
 722                regs->tpc &= 0xffffffff;
 723                regs->tnpc &= 0xffffffff;
 724        }
 725        if (++count <= 20)
 726                printk ("SunOS binary emulation not compiled in\n");
 727        force_sig(SIGSEGV, current);
 728
 729        return -ENOSYS;
 730}
 731#endif
 732
 733asmlinkage long sys_utrap_install(utrap_entry_t type,
 734                                  utrap_handler_t new_p,
 735                                  utrap_handler_t new_d,
 736                                  utrap_handler_t __user *old_p,
 737                                  utrap_handler_t __user *old_d)
 738{
 739        if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
 740                return -EINVAL;
 741        if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
 742                if (old_p) {
 743                        if (!current_thread_info()->utraps) {
 744                                if (put_user(NULL, old_p))
 745                                        return -EFAULT;
 746                        } else {
 747                                if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
 748                                        return -EFAULT;
 749                        }
 750                }
 751                if (old_d) {
 752                        if (put_user(NULL, old_d))
 753                                return -EFAULT;
 754                }
 755                return 0;
 756        }
 757        if (!current_thread_info()->utraps) {
 758                current_thread_info()->utraps =
 759                        kzalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
 760                if (!current_thread_info()->utraps)
 761                        return -ENOMEM;
 762                current_thread_info()->utraps[0] = 1;
 763        } else {
 764                if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p &&
 765                    current_thread_info()->utraps[0] > 1) {
 766                        unsigned long *p = current_thread_info()->utraps;
 767
 768                        current_thread_info()->utraps =
 769                                kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long),
 770                                        GFP_KERNEL);
 771                        if (!current_thread_info()->utraps) {
 772                                current_thread_info()->utraps = p;
 773                                return -ENOMEM;
 774                        }
 775                        p[0]--;
 776                        current_thread_info()->utraps[0] = 1;
 777                        memcpy(current_thread_info()->utraps+1, p+1,
 778                               UT_TRAP_INSTRUCTION_31*sizeof(long));
 779                }
 780        }
 781        if (old_p) {
 782                if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
 783                        return -EFAULT;
 784        }
 785        if (old_d) {
 786                if (put_user(NULL, old_d))
 787                        return -EFAULT;
 788        }
 789        current_thread_info()->utraps[type] = (long)new_p;
 790
 791        return 0;
 792}
 793
 794asmlinkage long sparc_memory_ordering(unsigned long model,
 795                                      struct pt_regs *regs)
 796{
 797        if (model >= 3)
 798                return -EINVAL;
 799        regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
 800        return 0;
 801}
 802
 803asmlinkage long sys_rt_sigaction(int sig,
 804                                 const struct sigaction __user *act,
 805                                 struct sigaction __user *oact,
 806                                 void __user *restorer,
 807                                 size_t sigsetsize)
 808{
 809        struct k_sigaction new_ka, old_ka;
 810        int ret;
 811
 812        /* XXX: Don't preclude handling different sized sigset_t's.  */
 813        if (sigsetsize != sizeof(sigset_t))
 814                return -EINVAL;
 815
 816        if (act) {
 817                new_ka.ka_restorer = restorer;
 818                if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
 819                        return -EFAULT;
 820        }
 821
 822        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 823
 824        if (!ret && oact) {
 825                if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
 826                        return -EFAULT;
 827        }
 828
 829        return ret;
 830}
 831
 832/* Invoked by rtrap code to update performance counters in
 833 * user space.
 834 */
 835asmlinkage void update_perfctrs(void)
 836{
 837        unsigned long pic, tmp;
 838
 839        read_pic(pic);
 840        tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
 841        __put_user(tmp, current_thread_info()->user_cntd0);
 842        tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
 843        __put_user(tmp, current_thread_info()->user_cntd1);
 844        reset_pic();
 845}
 846
 847asmlinkage long sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
 848{
 849        int err = 0;
 850
 851        switch(opcode) {
 852        case PERFCTR_ON:
 853                current_thread_info()->pcr_reg = arg2;
 854                current_thread_info()->user_cntd0 = (u64 __user *) arg0;
 855                current_thread_info()->user_cntd1 = (u64 __user *) arg1;
 856                current_thread_info()->kernel_cntd0 =
 857                        current_thread_info()->kernel_cntd1 = 0;
 858                write_pcr(arg2);
 859                reset_pic();
 860                set_thread_flag(TIF_PERFCTR);
 861                break;
 862
 863        case PERFCTR_OFF:
 864                err = -EINVAL;
 865                if (test_thread_flag(TIF_PERFCTR)) {
 866                        current_thread_info()->user_cntd0 =
 867                                current_thread_info()->user_cntd1 = NULL;
 868                        current_thread_info()->pcr_reg = 0;
 869                        write_pcr(0);
 870                        clear_thread_flag(TIF_PERFCTR);
 871                        err = 0;
 872                }
 873                break;
 874
 875        case PERFCTR_READ: {
 876                unsigned long pic, tmp;
 877
 878                if (!test_thread_flag(TIF_PERFCTR)) {
 879                        err = -EINVAL;
 880                        break;
 881                }
 882                read_pic(pic);
 883                tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
 884                err |= __put_user(tmp, current_thread_info()->user_cntd0);
 885                tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
 886                err |= __put_user(tmp, current_thread_info()->user_cntd1);
 887                reset_pic();
 888                break;
 889        }
 890
 891        case PERFCTR_CLRPIC:
 892                if (!test_thread_flag(TIF_PERFCTR)) {
 893                        err = -EINVAL;
 894                        break;
 895                }
 896                current_thread_info()->kernel_cntd0 =
 897                        current_thread_info()->kernel_cntd1 = 0;
 898                reset_pic();
 899                break;
 900
 901        case PERFCTR_SETPCR: {
 902                u64 __user *user_pcr = (u64 __user *)arg0;
 903
 904                if (!test_thread_flag(TIF_PERFCTR)) {
 905                        err = -EINVAL;
 906                        break;
 907                }
 908                err |= __get_user(current_thread_info()->pcr_reg, user_pcr);
 909                write_pcr(current_thread_info()->pcr_reg);
 910                current_thread_info()->kernel_cntd0 =
 911                        current_thread_info()->kernel_cntd1 = 0;
 912                reset_pic();
 913                break;
 914        }
 915
 916        case PERFCTR_GETPCR: {
 917                u64 __user *user_pcr = (u64 __user *)arg0;
 918
 919                if (!test_thread_flag(TIF_PERFCTR)) {
 920                        err = -EINVAL;
 921                        break;
 922                }
 923                err |= __put_user(current_thread_info()->pcr_reg, user_pcr);
 924                break;
 925        }
 926
 927        default:
 928                err = -EINVAL;
 929                break;
 930        };
 931        return err;
 932}
 933
 934/*
 935 * Do a system call from kernel instead of calling sys_execve so we
 936 * end up with proper pt_regs.
 937 */
 938int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 939{
 940        long __res;
 941        register long __g1 __asm__ ("g1") = __NR_execve;
 942        register long __o0 __asm__ ("o0") = (long)(filename);
 943        register long __o1 __asm__ ("o1") = (long)(argv);
 944        register long __o2 __asm__ ("o2") = (long)(envp);
 945        asm volatile ("t 0x6d\n\t"
 946                      "sub %%g0, %%o0, %0\n\t"
 947                      "movcc %%xcc, %%o0, %0\n\t"
 948                      : "=r" (__res), "=&r" (__o0)
 949                      : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
 950                      : "cc");
 951        return __res;
 952}
 953
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.