linux/arch/sh/kernel/sys_sh.c
<<
>>
Prefs
   1/*
   2 * linux/arch/sh/kernel/sys_sh.c
   3 *
   4 * This file contains various random system calls that
   5 * have a non-standard calling sequence on the Linux/SuperH
   6 * platform.
   7 *
   8 * Taken from i386 version.
   9 */
  10
  11#include <linux/errno.h>
  12#include <linux/sched.h>
  13#include <linux/mm.h>
  14#include <linux/smp.h>
  15#include <linux/sem.h>
  16#include <linux/msg.h>
  17#include <linux/shm.h>
  18#include <linux/stat.h>
  19#include <linux/syscalls.h>
  20#include <linux/mman.h>
  21#include <linux/file.h>
  22#include <linux/utsname.h>
  23#include <linux/module.h>
  24#include <linux/fs.h>
  25#include <linux/ipc.h>
  26#include <asm/cacheflush.h>
  27#include <asm/uaccess.h>
  28#include <asm/unistd.h>
  29
  30/*
  31 * sys_pipe() is the normal C calling standard for creating
  32 * a pipe. It's not the way Unix traditionally does this, though.
  33 */
  34asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
  35        unsigned long r6, unsigned long r7,
  36        struct pt_regs __regs)
  37{
  38        struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
  39        int fd[2];
  40        int error;
  41
  42        error = do_pipe(fd);
  43        if (!error) {
  44                regs->regs[1] = fd[1];
  45                return fd[0];
  46        }
  47        return error;
  48}
  49
  50unsigned long shm_align_mask = PAGE_SIZE - 1;   /* Sane caches */
  51
  52EXPORT_SYMBOL(shm_align_mask);
  53
  54#ifdef CONFIG_MMU
  55/*
  56 * To avoid cache aliases, we map the shared page with same color.
  57 */
  58#define COLOUR_ALIGN(addr, pgoff)                               \
  59        ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
  60         (((pgoff) << PAGE_SHIFT) & shm_align_mask))
  61
  62unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
  63        unsigned long len, unsigned long pgoff, unsigned long flags)
  64{
  65        struct mm_struct *mm = current->mm;
  66        struct vm_area_struct *vma;
  67        unsigned long start_addr;
  68        int do_colour_align;
  69
  70        if (flags & MAP_FIXED) {
  71                /* We do not accept a shared mapping if it would violate
  72                 * cache aliasing constraints.
  73                 */
  74                if ((flags & MAP_SHARED) && (addr & shm_align_mask))
  75                        return -EINVAL;
  76                return addr;
  77        }
  78
  79        if (unlikely(len > TASK_SIZE))
  80                return -ENOMEM;
  81
  82        do_colour_align = 0;
  83        if (filp || (flags & MAP_SHARED))
  84                do_colour_align = 1;
  85
  86        if (addr) {
  87                if (do_colour_align)
  88                        addr = COLOUR_ALIGN(addr, pgoff);
  89                else
  90                        addr = PAGE_ALIGN(addr);
  91
  92                vma = find_vma(mm, addr);
  93                if (TASK_SIZE - len >= addr &&
  94                    (!vma || addr + len <= vma->vm_start))
  95                        return addr;
  96        }
  97
  98        if (len > mm->cached_hole_size) {
  99                start_addr = addr = mm->free_area_cache;
 100        } else {
 101                mm->cached_hole_size = 0;
 102                start_addr = addr = TASK_UNMAPPED_BASE;
 103        }
 104
 105full_search:
 106        if (do_colour_align)
 107                addr = COLOUR_ALIGN(addr, pgoff);
 108        else
 109                addr = PAGE_ALIGN(mm->free_area_cache);
 110
 111        for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
 112                /* At this point:  (!vma || addr < vma->vm_end). */
 113                if (unlikely(TASK_SIZE - len < addr)) {
 114                        /*
 115                         * Start a new search - just in case we missed
 116                         * some holes.
 117                         */
 118                        if (start_addr != TASK_UNMAPPED_BASE) {
 119                                start_addr = addr = TASK_UNMAPPED_BASE;
 120                                mm->cached_hole_size = 0;
 121                                goto full_search;
 122                        }
 123                        return -ENOMEM;
 124                }
 125                if (likely(!vma || addr + len <= vma->vm_start)) {
 126                        /*
 127                         * Remember the place where we stopped the search:
 128                         */
 129                        mm->free_area_cache = addr + len;
 130                        return addr;
 131                }
 132                if (addr + mm->cached_hole_size < vma->vm_start)
 133                        mm->cached_hole_size = vma->vm_start - addr;
 134
 135                addr = vma->vm_end;
 136                if (do_colour_align)
 137                        addr = COLOUR_ALIGN(addr, pgoff);
 138        }
 139}
 140#endif /* CONFIG_MMU */
 141
 142static inline long
 143do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
 144         unsigned long flags, int fd, unsigned long pgoff)
 145{
 146        int error = -EBADF;
 147        struct file *file = NULL;
 148
 149        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 150        if (!(flags & MAP_ANONYMOUS)) {
 151                file = fget(fd);
 152                if (!file)
 153                        goto out;
 154        }
 155
 156        down_write(&current->mm->mmap_sem);
 157        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 158        up_write(&current->mm->mmap_sem);
 159
 160        if (file)
 161                fput(file);
 162out:
 163        return error;
 164}
 165
 166asmlinkage int old_mmap(unsigned long addr, unsigned long len,
 167        unsigned long prot, unsigned long flags,
 168        int fd, unsigned long off)
 169{
 170        if (off & ~PAGE_MASK)
 171                return -EINVAL;
 172        return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
 173}
 174
 175asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
 176        unsigned long prot, unsigned long flags,
 177        unsigned long fd, unsigned long pgoff)
 178{
 179        return do_mmap2(addr, len, prot, flags, fd, pgoff);
 180}
 181
 182/*
 183 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
 184 *
 185 * This is really horribly ugly.
 186 */
 187asmlinkage int sys_ipc(uint call, int first, int second,
 188                       int third, void __user *ptr, long fifth)
 189{
 190        int version, ret;
 191
 192        version = call >> 16; /* hack for backward compatibility */
 193        call &= 0xffff;
 194
 195        if (call <= SEMCTL)
 196                switch (call) {
 197                case SEMOP:
 198                        return sys_semtimedop(first, (struct sembuf __user *)ptr,
 199                                              second, NULL);
 200                case SEMTIMEDOP:
 201                        return sys_semtimedop(first, (struct sembuf __user *)ptr,
 202                                              second,
 203                                              (const struct timespec __user *)fifth);
 204                case SEMGET:
 205                        return sys_semget (first, second, third);
 206                case SEMCTL: {
 207                        union semun fourth;
 208                        if (!ptr)
 209                                return -EINVAL;
 210                        if (get_user(fourth.__pad, (void * __user *) ptr))
 211                                return -EFAULT;
 212                        return sys_semctl (first, second, third, fourth);
 213                        }
 214                default:
 215                        return -EINVAL;
 216                }
 217
 218        if (call <= MSGCTL) 
 219                switch (call) {
 220                case MSGSND:
 221                        return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
 222                                          second, third);
 223                case MSGRCV:
 224                        switch (version) {
 225                        case 0: {
 226                                struct ipc_kludge tmp;
 227                                if (!ptr)
 228                                        return -EINVAL;
 229                                
 230                                if (copy_from_user(&tmp,
 231                                                   (struct ipc_kludge __user *) ptr, 
 232                                                   sizeof (tmp)))
 233                                        return -EFAULT;
 234                                return sys_msgrcv (first, tmp.msgp, second,
 235                                                   tmp.msgtyp, third);
 236                                }
 237                        default:
 238                                return sys_msgrcv (first,
 239                                                   (struct msgbuf __user *) ptr,
 240                                                   second, fifth, third);
 241                        }
 242                case MSGGET:
 243                        return sys_msgget ((key_t) first, second);
 244                case MSGCTL:
 245                        return sys_msgctl (first, second,
 246                                           (struct msqid_ds __user *) ptr);
 247                default:
 248                        return -EINVAL;
 249                }
 250        if (call <= SHMCTL) 
 251                switch (call) {
 252                case SHMAT:
 253                        switch (version) {
 254                        default: {
 255                                ulong raddr;
 256                                ret = do_shmat (first, (char __user *) ptr,
 257                                                 second, &raddr);
 258                                if (ret)
 259                                        return ret;
 260                                return put_user (raddr, (ulong __user *) third);
 261                        }
 262                        case 1: /* iBCS2 emulator entry point */
 263                                if (!segment_eq(get_fs(), get_ds()))
 264                                        return -EINVAL;
 265                                return do_shmat (first, (char __user *) ptr,
 266                                                  second, (ulong *) third);
 267                        }
 268                case SHMDT: 
 269                        return sys_shmdt ((char __user *)ptr);
 270                case SHMGET:
 271                        return sys_shmget (first, second, third);
 272                case SHMCTL:
 273                        return sys_shmctl (first, second,
 274                                           (struct shmid_ds __user *) ptr);
 275                default:
 276                        return -EINVAL;
 277                }
 278        
 279        return -EINVAL;
 280}
 281
 282asmlinkage int sys_uname(struct old_utsname * name)
 283{
 284        int err;
 285        if (!name)
 286                return -EFAULT;
 287        down_read(&uts_sem);
 288        err = copy_to_user(name, utsname(), sizeof (*name));
 289        up_read(&uts_sem);
 290        return err?-EFAULT:0;
 291}
 292
 293asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
 294                             size_t count, long dummy, loff_t pos)
 295{
 296        return sys_pread64(fd, buf, count, pos);
 297}
 298
 299asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
 300                              size_t count, long dummy, loff_t pos)
 301{
 302        return sys_pwrite64(fd, buf, count, pos);
 303}
 304
 305asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
 306                                u32 len0, u32 len1, int advice)
 307{
 308#ifdef  __LITTLE_ENDIAN__
 309        return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
 310                                (u64)len1 << 32 | len0, advice);
 311#else
 312        return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
 313                                (u64)len0 << 32 | len1, advice);
 314#endif
 315}
 316
 317#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
 318#define SYSCALL_ARG3    "trapa #0x23"
 319#else
 320#define SYSCALL_ARG3    "trapa #0x13"
 321#endif
 322
 323/*
 324 * Do a system call from kernel instead of calling sys_execve so we
 325 * end up with proper pt_regs.
 326 */
 327int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 328{
 329        register long __sc0 __asm__ ("r3") = __NR_execve;
 330        register long __sc4 __asm__ ("r4") = (long) filename;
 331        register long __sc5 __asm__ ("r5") = (long) argv;
 332        register long __sc6 __asm__ ("r6") = (long) envp;
 333        __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)       
 334                        : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
 335                        : "memory");
 336        return __sc0;
 337}
 338