linux/arch/ia64/kernel/sys_ia64.c
<<
>>
Prefs
   1/*
   2 * This file contains various system calls that have different calling
   3 * conventions on different platforms.
   4 *
   5 * Copyright (C) 1999-2000, 2002-2003, 2005 Hewlett-Packard Co
   6 *      David Mosberger-Tang <davidm@hpl.hp.com>
   7 */
   8#include <linux/errno.h>
   9#include <linux/fs.h>
  10#include <linux/mm.h>
  11#include <linux/mman.h>
  12#include <linux/sched.h>
  13#include <linux/shm.h>
  14#include <linux/file.h>         /* doh, must come after sched.h... */
  15#include <linux/smp.h>
  16#include <linux/syscalls.h>
  17#include <linux/highuid.h>
  18#include <linux/hugetlb.h>
  19
  20#include <asm/shmparam.h>
  21#include <asm/uaccess.h>
  22
  23unsigned long
  24arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len,
  25                        unsigned long pgoff, unsigned long flags)
  26{
  27        long map_shared = (flags & MAP_SHARED);
  28        unsigned long start_addr, align_mask = PAGE_SIZE - 1;
  29        struct mm_struct *mm = current->mm;
  30        struct vm_area_struct *vma;
  31
  32        if (len > RGN_MAP_LIMIT)
  33                return -ENOMEM;
  34
  35        /* handle fixed mapping: prevent overlap with huge pages */
  36        if (flags & MAP_FIXED) {
  37                if (is_hugepage_only_range(mm, addr, len))
  38                        return -EINVAL;
  39                return addr;
  40        }
  41
  42#ifdef CONFIG_HUGETLB_PAGE
  43        if (REGION_NUMBER(addr) == RGN_HPAGE)
  44                addr = 0;
  45#endif
  46        if (!addr)
  47                addr = mm->free_area_cache;
  48
  49        if (map_shared && (TASK_SIZE > 0xfffffffful))
  50                /*
  51                 * For 64-bit tasks, align shared segments to 1MB to avoid potential
  52                 * performance penalty due to virtual aliasing (see ASDM).  For 32-bit
  53                 * tasks, we prefer to avoid exhausting the address space too quickly by
  54                 * limiting alignment to a single page.
  55                 */
  56                align_mask = SHMLBA - 1;
  57
  58  full_search:
  59        start_addr = addr = (addr + align_mask) & ~align_mask;
  60
  61        for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
  62                /* At this point:  (!vma || addr < vma->vm_end). */
  63                if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) {
  64                        if (start_addr != TASK_UNMAPPED_BASE) {
  65                                /* Start a new search --- just in case we missed some holes.  */
  66                                addr = TASK_UNMAPPED_BASE;
  67                                goto full_search;
  68                        }
  69                        return -ENOMEM;
  70                }
  71                if (!vma || addr + len <= vma->vm_start) {
  72                        /* Remember the address where we stopped this search:  */
  73                        mm->free_area_cache = addr + len;
  74                        return addr;
  75                }
  76                addr = (vma->vm_end + align_mask) & ~align_mask;
  77        }
  78}
  79
  80asmlinkage long
  81ia64_getpriority (int which, int who)
  82{
  83        long prio;
  84
  85        prio = sys_getpriority(which, who);
  86        if (prio >= 0) {
  87                force_successful_syscall_return();
  88                prio = 20 - prio;
  89        }
  90        return prio;
  91}
  92
  93/* XXX obsolete, but leave it here until the old libc is gone... */
  94asmlinkage unsigned long
  95sys_getpagesize (void)
  96{
  97        return PAGE_SIZE;
  98}
  99
 100asmlinkage unsigned long
 101ia64_brk (unsigned long brk)
 102{
 103        unsigned long rlim, retval, newbrk, oldbrk;
 104        struct mm_struct *mm = current->mm;
 105
 106        /*
 107         * Most of this replicates the code in sys_brk() except for an additional safety
 108         * check and the clearing of r8.  However, we can't call sys_brk() because we need
 109         * to acquire the mmap_sem before we can do the test...
 110         */
 111        down_write(&mm->mmap_sem);
 112
 113        if (brk < mm->end_code)
 114                goto out;
 115        newbrk = PAGE_ALIGN(brk);
 116        oldbrk = PAGE_ALIGN(mm->brk);
 117        if (oldbrk == newbrk)
 118                goto set_brk;
 119
 120        /* Always allow shrinking brk. */
 121        if (brk <= mm->brk) {
 122                if (!do_munmap(mm, newbrk, oldbrk-newbrk))
 123                        goto set_brk;
 124                goto out;
 125        }
 126
 127        /* Check against unimplemented/unmapped addresses: */
 128        if ((newbrk - oldbrk) > RGN_MAP_LIMIT || REGION_OFFSET(newbrk) > RGN_MAP_LIMIT)
 129                goto out;
 130
 131        /* Check against rlimit.. */
 132        rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
 133        if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
 134                goto out;
 135
 136        /* Check against existing mmap mappings. */
 137        if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
 138                goto out;
 139
 140        /* Ok, looks good - let it rip. */
 141        if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
 142                goto out;
 143set_brk:
 144        mm->brk = brk;
 145out:
 146        retval = mm->brk;
 147        up_write(&mm->mmap_sem);
 148        force_successful_syscall_return();
 149        return retval;
 150}
 151
 152/*
 153 * On IA-64, we return the two file descriptors in ret0 and ret1 (r8
 154 * and r9) as this is faster than doing a copy_to_user().
 155 */
 156asmlinkage long
 157sys_pipe (void)
 158{
 159        struct pt_regs *regs = task_pt_regs(current);
 160        int fd[2];
 161        int retval;
 162
 163        retval = do_pipe(fd);
 164        if (retval)
 165                goto out;
 166        retval = fd[0];
 167        regs->r9 = fd[1];
 168  out:
 169        return retval;
 170}
 171
 172int ia64_mmap_check(unsigned long addr, unsigned long len,
 173                unsigned long flags)
 174{
 175        unsigned long roff;
 176
 177        /*
 178         * Don't permit mappings into unmapped space, the virtual page table
 179         * of a region, or across a region boundary.  Note: RGN_MAP_LIMIT is
 180         * equal to 2^n-PAGE_SIZE (for some integer n <= 61) and len > 0.
 181         */
 182        roff = REGION_OFFSET(addr);
 183        if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len)))
 184                return -EINVAL;
 185        return 0;
 186}
 187
 188static inline unsigned long
 189do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff)
 190{
 191        struct file *file = NULL;
 192
 193        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 194        if (!(flags & MAP_ANONYMOUS)) {
 195                file = fget(fd);
 196                if (!file)
 197                        return -EBADF;
 198
 199                if (!file->f_op || !file->f_op->mmap) {
 200                        addr = -ENODEV;
 201                        goto out;
 202                }
 203        }
 204
 205        /* Careful about overflows.. */
 206        len = PAGE_ALIGN(len);
 207        if (!len || len > TASK_SIZE) {
 208                addr = -EINVAL;
 209                goto out;
 210        }
 211
 212        down_write(&current->mm->mmap_sem);
 213        addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 214        up_write(&current->mm->mmap_sem);
 215
 216out:    if (file)
 217                fput(file);
 218        return addr;
 219}
 220
 221/*
 222 * mmap2() is like mmap() except that the offset is expressed in units
 223 * of PAGE_SIZE (instead of bytes).  This allows to mmap2() (pieces
 224 * of) files that are larger than the address space of the CPU.
 225 */
 226asmlinkage unsigned long
 227sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff)
 228{
 229        addr = do_mmap2(addr, len, prot, flags, fd, pgoff);
 230        if (!IS_ERR((void *) addr))
 231                force_successful_syscall_return();
 232        return addr;
 233}
 234
 235asmlinkage unsigned long
 236sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, int fd, long off)
 237{
 238        if (offset_in_page(off) != 0)
 239                return -EINVAL;
 240
 241        addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 242        if (!IS_ERR((void *) addr))
 243                force_successful_syscall_return();
 244        return addr;
 245}
 246
 247asmlinkage unsigned long
 248ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
 249             unsigned long new_addr)
 250{
 251        extern unsigned long do_mremap (unsigned long addr,
 252                                        unsigned long old_len,
 253                                        unsigned long new_len,
 254                                        unsigned long flags,
 255                                        unsigned long new_addr);
 256
 257        down_write(&current->mm->mmap_sem);
 258        {
 259                addr = do_mremap(addr, old_len, new_len, flags, new_addr);
 260        }
 261        up_write(&current->mm->mmap_sem);
 262
 263        if (IS_ERR((void *) addr))
 264                return addr;
 265
 266        force_successful_syscall_return();
 267        return addr;
 268}
 269
 270#ifndef CONFIG_PCI
 271
 272asmlinkage long
 273sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
 274                    void *buf)
 275{
 276        return -ENOSYS;
 277}
 278
 279asmlinkage long
 280sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
 281                     void *buf)
 282{
 283        return -ENOSYS;
 284}
 285
 286#endif /* CONFIG_PCI */
 287