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 #include <linux/errno.h> 11 #include <linux/sched.h> 12 #include <linux/mm.h> 13 #include <linux/smp.h> 14 #include <linux/sem.h> 15 #include <linux/msg.h> 16 #include <linux/shm.h> 17 #include <linux/stat.h> 18 #include <linux/syscalls.h> 19 #include <linux/mman.h> 20 #include <linux/file.h> 21 #include <linux/utsname.h> 22 #include <linux/module.h> 23 #include <linux/fs.h> 24 #include <linux/ipc.h> 25 #include <asm/cacheflush.h> 26 #include <asm/syscalls.h> 27 #include <asm/uaccess.h> 28 #include <asm/unistd.h> 29 30 unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ 31 EXPORT_SYMBOL(shm_align_mask); 32 33 #ifdef CONFIG_MMU 34 /* 35 * To avoid cache aliases, we map the shared page with same color. 36 */ 37 #define COLOUR_ALIGN(addr, pgoff) \ 38 ((((addr) + shm_align_mask) & ~shm_align_mask) + \ 39 (((pgoff) << PAGE_SHIFT) & shm_align_mask)) 40 41 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, 42 unsigned long len, unsigned long pgoff, unsigned long flags) 43 { 44 struct mm_struct *mm = current->mm; 45 struct vm_area_struct *vma; 46 unsigned long start_addr; 47 int do_colour_align; 48 49 if (flags & MAP_FIXED) { 50 /* We do not accept a shared mapping if it would violate 51 * cache aliasing constraints. 52 */ 53 if ((flags & MAP_SHARED) && (addr & shm_align_mask)) 54 return -EINVAL; 55 return addr; 56 } 57 58 if (unlikely(len > TASK_SIZE)) 59 return -ENOMEM; 60 61 do_colour_align = 0; 62 if (filp || (flags & MAP_SHARED)) 63 do_colour_align = 1; 64 65 if (addr) { 66 if (do_colour_align) 67 addr = COLOUR_ALIGN(addr, pgoff); 68 else 69 addr = PAGE_ALIGN(addr); 70 71 vma = find_vma(mm, addr); 72 if (TASK_SIZE - len >= addr && 73 (!vma || addr + len <= vma->vm_start)) 74 return addr; 75 } 76 77 if (len > mm->cached_hole_size) { 78 start_addr = addr = mm->free_area_cache; 79 } else { 80 mm->cached_hole_size = 0; 81 start_addr = addr = TASK_UNMAPPED_BASE; 82 } 83 84 full_search: 85 if (do_colour_align) 86 addr = COLOUR_ALIGN(addr, pgoff); 87 else 88 addr = PAGE_ALIGN(mm->free_area_cache); 89 90 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { 91 /* At this point: (!vma || addr < vma->vm_end). */ 92 if (unlikely(TASK_SIZE - len < addr)) { 93 /* 94 * Start a new search - just in case we missed 95 * some holes. 96 */ 97 if (start_addr != TASK_UNMAPPED_BASE) { 98 start_addr = addr = TASK_UNMAPPED_BASE; 99 mm->cached_hole_size = 0; 100 goto full_search; 101 } 102 return -ENOMEM; 103 } 104 if (likely(!vma || addr + len <= vma->vm_start)) { 105 /* 106 * Remember the place where we stopped the search: 107 */ 108 mm->free_area_cache = addr + len; 109 return addr; 110 } 111 if (addr + mm->cached_hole_size < vma->vm_start) 112 mm->cached_hole_size = vma->vm_start - addr; 113 114 addr = vma->vm_end; 115 if (do_colour_align) 116 addr = COLOUR_ALIGN(addr, pgoff); 117 } 118 } 119 #endif /* CONFIG_MMU */ 120 121 static inline long 122 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 123 unsigned long flags, int fd, unsigned long pgoff) 124 { 125 int error = -EBADF; 126 struct file *file = NULL; 127 128 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 129 if (!(flags & MAP_ANONYMOUS)) { 130 file = fget(fd); 131 if (!file) 132 goto out; 133 } 134 135 down_write(¤t->mm->mmap_sem); 136 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 137 up_write(¤t->mm->mmap_sem); 138 139 if (file) 140 fput(file); 141 out: 142 return error; 143 } 144 145 asmlinkage int old_mmap(unsigned long addr, unsigned long len, 146 unsigned long prot, unsigned long flags, 147 int fd, unsigned long off) 148 { 149 if (off & ~PAGE_MASK) 150 return -EINVAL; 151 return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); 152 } 153 154 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 155 unsigned long prot, unsigned long flags, 156 unsigned long fd, unsigned long pgoff) 157 { 158 return do_mmap2(addr, len, prot, flags, fd, pgoff); 159 } 160 161 /* 162 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 163 * 164 * This is really horribly ugly. 165 */ 166 asmlinkage int sys_ipc(uint call, int first, int second, 167 int third, void __user *ptr, long fifth) 168 { 169 int version, ret; 170 171 version = call >> 16; /* hack for backward compatibility */ 172 call &= 0xffff; 173 174 trace_mark(kernel_arch_ipc_call, "call %u first %d", call, first); 175 176 if (call <= SEMTIMEDOP) 177 switch (call) { 178 case SEMOP: 179 return sys_semtimedop(first, 180 (struct sembuf __user *)ptr, 181 second, NULL); 182 case SEMTIMEDOP: 183 return sys_semtimedop(first, 184 (struct sembuf __user *)ptr, second, 185 (const struct timespec __user *)fifth); 186 case SEMGET: 187 return sys_semget (first, second, third); 188 case SEMCTL: { 189 union semun fourth; 190 if (!ptr) 191 return -EINVAL; 192 if (get_user(fourth.__pad, (void __user * __user *) ptr)) 193 return -EFAULT; 194 return sys_semctl (first, second, third, fourth); 195 } 196 default: 197 return -EINVAL; 198 } 199 200 if (call <= MSGCTL) 201 switch (call) { 202 case MSGSND: 203 return sys_msgsnd (first, (struct msgbuf __user *) ptr, 204 second, third); 205 case MSGRCV: 206 switch (version) { 207 case 0: 208 { 209 struct ipc_kludge tmp; 210 211 if (!ptr) 212 return -EINVAL; 213 214 if (copy_from_user(&tmp, 215 (struct ipc_kludge __user *) ptr, 216 sizeof (tmp))) 217 return -EFAULT; 218 219 return sys_msgrcv (first, tmp.msgp, second, 220 tmp.msgtyp, third); 221 } 222 default: 223 return sys_msgrcv (first, 224 (struct msgbuf __user *) ptr, 225 second, fifth, third); 226 } 227 case MSGGET: 228 return sys_msgget ((key_t) first, second); 229 case MSGCTL: 230 return sys_msgctl (first, second, 231 (struct msqid_ds __user *) ptr); 232 default: 233 return -EINVAL; 234 } 235 if (call <= SHMCTL) 236 switch (call) { 237 case SHMAT: 238 switch (version) { 239 default: { 240 ulong raddr; 241 ret = do_shmat (first, (char __user *) ptr, 242 second, &raddr); 243 if (ret) 244 return ret; 245 return put_user (raddr, (ulong __user *) third); 246 } 247 case 1: /* iBCS2 emulator entry point */ 248 if (!segment_eq(get_fs(), get_ds())) 249 return -EINVAL; 250 return do_shmat (first, (char __user *) ptr, 251 second, (ulong *) third); 252 } 253 case SHMDT: 254 return sys_shmdt ((char __user *)ptr); 255 case SHMGET: 256 return sys_shmget (first, second, third); 257 case SHMCTL: 258 return sys_shmctl (first, second, 259 (struct shmid_ds __user *) ptr); 260 default: 261 return -EINVAL; 262 } 263 264 return -EINVAL; 265 } 266 267 asmlinkage int sys_uname(struct old_utsname __user *name) 268 { 269 int err; 270 if (!name) 271 return -EFAULT; 272 down_read(&uts_sem); 273 err = copy_to_user(name, utsname(), sizeof(*name)); 274 up_read(&uts_sem); 275 return err?-EFAULT:0; 276 } 277