sh: fix sys_cacheflush error checking
[safe/jmp/linux-2.6] / arch / sh / kernel / sys_sh.c
index 917b2f3..8aa5d1c 100644 (file)
@@ -7,12 +7,10 @@
  *
  * Taken from i386 version.
  */
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
-
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/ipc.h>
+#include <asm/syscalls.h>
 #include <asm/uaccess.h>
-#include <asm/ipc.h>
-
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way Unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
-       unsigned long r6, unsigned long r7,
-       struct pt_regs regs)
-{
-       int fd[2];
-       int error;
-
-       error = do_pipe(fd);
-       if (!error) {
-               regs.regs[1] = fd[1];
-               return fd[0];
-       }
-       return error;
-}
-
-#if defined(HAVE_ARCH_UNMAPPED_AREA)
-/*
- * To avoid cache alias, we map the shard page with same color.
- */
-#define COLOUR_ALIGN(addr)     (((addr)+SHMLBA-1)&~(SHMLBA-1))
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-       unsigned long len, unsigned long pgoff, unsigned long flags)
-{
-       struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma;
-       unsigned long start_addr;
-
-       if (flags & MAP_FIXED) {
-               /* We do not accept a shared mapping if it would violate
-                * cache aliasing constraints.
-                */
-               if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
-                       return -EINVAL;
-               return addr;
-       }
-
-       if (len > TASK_SIZE)
-               return -ENOMEM;
-
-       if (addr) {
-               if (flags & MAP_PRIVATE)
-                       addr = PAGE_ALIGN(addr);
-               else
-                       addr = COLOUR_ALIGN(addr);
-               vma = find_vma(mm, addr);
-               if (TASK_SIZE - len >= addr &&
-                   (!vma || addr + len <= vma->vm_start))
-                       return addr;
-       }
-       if (len <= mm->cached_hole_size) {
-               mm->cached_hole_size = 0;
-               mm->free_area_cache = TASK_UNMAPPED_BASE;
-       }
-       if (flags & MAP_PRIVATE)
-               addr = PAGE_ALIGN(mm->free_area_cache);
-       else
-               addr = COLOUR_ALIGN(mm->free_area_cache);
-       start_addr = addr;
-
-full_search:
-       for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
-               /* At this point:  (!vma || addr < vma->vm_end). */
-               if (TASK_SIZE - len < addr) {
-                       /*
-                        * Start a new search - just in case we missed
-                        * some holes.
-                        */
-                       if (start_addr != TASK_UNMAPPED_BASE) {
-                               start_addr = addr = TASK_UNMAPPED_BASE;
-                               mm->cached_hole_size = 0;
-                               goto full_search;
-                       }
-                       return -ENOMEM;
-               }
-               if (!vma || addr + len <= vma->vm_start) {
-                       /*
-                        * Remember the place where we stopped the search:
-                        */
-                       mm->free_area_cache = addr + len;
-                       return addr;
-               }
-               if (addr + mm->cached_hole_size < vma->vm_start)
-                       mm->cached_hole_size = vma->vm_start - addr;
-
-               addr = vma->vm_end;
-               if (!(flags & MAP_PRIVATE))
-                       addr = COLOUR_ALIGN(addr);
-       }
-}
-#endif
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+#include <asm/cachectl.h>
 
 static inline long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
         unsigned long flags, int fd, unsigned long pgoff)
 {
        int error = -EBADF;
@@ -158,6 +65,15 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags,
        unsigned long fd, unsigned long pgoff)
 {
+       /*
+        * The shift for mmap2 is constant, regardless of PAGE_SIZE
+        * setting.
+        */
+       if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1))
+               return -EINVAL;
+
+       pgoff >>= PAGE_SHIFT - 12;
+
        return do_mmap2(addr, len, prot, flags, fd, pgoff);
 }
 
@@ -174,22 +90,23 @@ asmlinkage int sys_ipc(uint call, int first, int second,
        version = call >> 16; /* hack for backward compatibility */
        call &= 0xffff;
 
-       if (call <= SEMCTL)
+       if (call <= SEMTIMEDOP)
                switch (call) {
                case SEMOP:
-                       return sys_semtimedop(first, (struct sembuf __user *)ptr,
+                       return sys_semtimedop(first,
+                                             (struct sembuf __user *)ptr,
                                              second, NULL);
                case SEMTIMEDOP:
-                       return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                             second,
-                                             (const struct timespec __user *)fifth);
+                       return sys_semtimedop(first,
+                               (struct sembuf __user *)ptr, second,
+                               (const struct timespec __user *)fifth);
                case SEMGET:
                        return sys_semget (first, second, third);
                case SEMCTL: {
                        union semun fourth;
                        if (!ptr)
                                return -EINVAL;
-                       if (get_user(fourth.__pad, (void * __user *) ptr))
+                       if (get_user(fourth.__pad, (void __user * __user *) ptr))
                                return -EFAULT;
                        return sys_semctl (first, second, third, fourth);
                        }
@@ -197,25 +114,28 @@ asmlinkage int sys_ipc(uint call, int first, int second,
                        return -EINVAL;
                }
 
-       if (call <= MSGCTL) 
+       if (call <= MSGCTL)
                switch (call) {
                case MSGSND:
-                       return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
+                       return sys_msgsnd (first, (struct msgbuf __user *) ptr,
                                          second, third);
                case MSGRCV:
                        switch (version) {
-                       case 0: {
+                       case 0:
+                       {
                                struct ipc_kludge tmp;
+
                                if (!ptr)
                                        return -EINVAL;
-                               
+
                                if (copy_from_user(&tmp,
-                                                  (struct ipc_kludge __user *) ptr, 
+                                       (struct ipc_kludge __user *) ptr,
                                                   sizeof (tmp)))
                                        return -EFAULT;
+
                                return sys_msgrcv (first, tmp.msgp, second,
                                                   tmp.msgtyp, third);
-                               }
+                       }
                        default:
                                return sys_msgrcv (first,
                                                   (struct msgbuf __user *) ptr,
@@ -229,7 +149,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
                default:
                        return -EINVAL;
                }
-       if (call <= SHMCTL) 
+       if (call <= SHMCTL)
                switch (call) {
                case SHMAT:
                        switch (version) {
@@ -247,7 +167,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
                                return do_shmat (first, (char __user *) ptr,
                                                  second, (ulong *) third);
                        }
-               case SHMDT: 
+               case SHMDT:
                        return sys_shmdt ((char __user *)ptr);
                case SHMGET:
                        return sys_shmget (first, second, third);
@@ -257,41 +177,58 @@ asmlinkage int sys_ipc(uint call, int first, int second,
                default:
                        return -EINVAL;
                }
-       
+
        return -EINVAL;
 }
 
-asmlinkage int sys_uname(struct old_utsname * name)
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op)
 {
-       int err;
-       if (!name)
+       struct vm_area_struct *vma;
+
+       if ((op <= 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I)))
+               return -EINVAL;
+
+       /*
+        * Verify that the specified address region actually belongs
+        * to this process.
+        */
+       if (addr + len < addr)
                return -EFAULT;
-       down_read(&uts_sem);
-       err=copy_to_user(name, &system_utsname, sizeof (*name));
-       up_read(&uts_sem);
-       return err?-EFAULT:0;
-}
 
-asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
-                            size_t count, long dummy, loff_t pos)
-{
-       return sys_pread64(fd, buf, count, pos);
-}
+       down_read(&current->mm->mmap_sem);
+       vma = find_vma (current->mm, addr);
+       if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) {
+               up_read(&current->mm->mmap_sem);
+               return -EFAULT;
+       }
 
-asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
-                             size_t count, long dummy, loff_t pos)
-{
-       return sys_pwrite64(fd, buf, count, pos);
+       switch (op & CACHEFLUSH_D_PURGE) {
+               case CACHEFLUSH_D_INVAL:
+                       __flush_invalidate_region((void *)addr, len);
+                       break;
+               case CACHEFLUSH_D_WB:
+                       __flush_wback_region((void *)addr, len);
+                       break;
+               case CACHEFLUSH_D_PURGE:
+                       __flush_purge_region((void *)addr, len);
+                       break;
+       }
+
+       if (op & CACHEFLUSH_I)
+               flush_cache_all();
+
+       up_read(&current->mm->mmap_sem);
+       return 0;
 }
 
-asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
-                               u32 len0, u32 len1, int advice)
+asmlinkage int sys_uname(struct old_utsname __user *name)
 {
-#ifdef  __LITTLE_ENDIAN__
-       return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
-                               (u64)len1 << 32 | len0, advice);
-#else
-       return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
-                               (u64)len0 << 32 | len1, advice);
-#endif
+       int err;
+       if (!name)
+               return -EFAULT;
+       down_read(&uts_sem);
+       err = copy_to_user(name, utsname(), sizeof(*name));
+       up_read(&uts_sem);
+       return err?-EFAULT:0;
 }