1 /* 2 * linux/arch/arm/kernel/sys_arm.c 3 * 4 * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c 5 * Copyright (C) 1995, 1996 Russell King. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This file contains various random system calls that 12 * have a non-standard calling sequence on the Linux/arm 13 * platform. 14 */ 15 #include <linux/module.h> 16 #include <linux/errno.h> 17 #include <linux/sched.h> 18 #include <linux/slab.h> 19 #include <linux/mm.h> 20 #include <linux/sem.h> 21 #include <linux/msg.h> 22 #include <linux/shm.h> 23 #include <linux/stat.h> 24 #include <linux/syscalls.h> 25 #include <linux/mman.h> 26 #include <linux/fs.h> 27 #include <linux/file.h> 28 #include <linux/utsname.h> 29 #include <linux/ipc.h> 30 #include <linux/uaccess.h> 31 32 extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, 33 unsigned long new_len, unsigned long flags, 34 unsigned long new_addr); 35 36 /* common code for old and new mmaps */ 37 inline long do_mmap2( 38 unsigned long addr, unsigned long len, 39 unsigned long prot, unsigned long flags, 40 unsigned long fd, unsigned long pgoff) 41 { 42 int error = -EINVAL; 43 struct file * file = NULL; 44 45 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 46 47 if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS) 48 goto out; 49 50 error = -EBADF; 51 if (!(flags & MAP_ANONYMOUS)) { 52 file = fget(fd); 53 if (!file) 54 goto out; 55 } 56 57 down_write(¤t->mm->mmap_sem); 58 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 59 up_write(¤t->mm->mmap_sem); 60 61 if (file) 62 fput(file); 63 out: 64 return error; 65 } 66 67 struct mmap_arg_struct { 68 unsigned long addr; 69 unsigned long len; 70 unsigned long prot; 71 unsigned long flags; 72 unsigned long fd; 73 unsigned long offset; 74 }; 75 76 asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) 77 { 78 int error = -EFAULT; 79 struct mmap_arg_struct a; 80 81 if (copy_from_user(&a, arg, sizeof(a))) 82 goto out; 83 84 error = -EINVAL; 85 if (a.offset & ~PAGE_MASK) 86 goto out; 87 88 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); 89 out: 90 return error; 91 } 92 93 asmlinkage unsigned long 94 sys_arm_mremap(unsigned long addr, unsigned long old_len, 95 unsigned long new_len, unsigned long flags, 96 unsigned long new_addr) 97 { 98 unsigned long ret = -EINVAL; 99 100 if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) 101 goto out; 102 103 down_write(¤t->mm->mmap_sem); 104 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 105 up_write(¤t->mm->mmap_sem); 106 107 out: 108 return ret; 109 } 110 111 /* 112 * Perform the select(nd, in, out, ex, tv) and mmap() system 113 * calls. 114 */ 115 116 struct sel_arg_struct { 117 unsigned long n; 118 fd_set __user *inp, *outp, *exp; 119 struct timeval __user *tvp; 120 }; 121 122 asmlinkage int old_select(struct sel_arg_struct __user *arg) 123 { 124 struct sel_arg_struct a; 125 126 if (copy_from_user(&a, arg, sizeof(a))) 127 return -EFAULT; 128 /* sys_select() does the appropriate kernel locking */ 129 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); 130 } 131 132 #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) 133 /* 134 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 135 * 136 * This is really horribly ugly. 137 */ 138 asmlinkage int sys_ipc(uint call, int first, int second, int third, 139 void __user *ptr, long fifth) 140 { 141 int version, ret; 142 143 version = call >> 16; /* hack for backward compatibility */ 144 call &= 0xffff; 145 146 switch (call) { 147 case SEMOP: 148 return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); 149 case SEMTIMEDOP: 150 return sys_semtimedop(first, (struct sembuf __user *)ptr, second, 151 (const struct timespec __user *)fifth); 152 153 case SEMGET: 154 return sys_semget (first, second, third); 155 case SEMCTL: { 156 union semun fourth; 157 if (!ptr) 158 return -EINVAL; 159 if (get_user(fourth.__pad, (void __user * __user *) ptr)) 160 return -EFAULT; 161 return sys_semctl (first, second, third, fourth); 162 } 163 164 case MSGSND: 165 return sys_msgsnd(first, (struct msgbuf __user *) ptr, 166 second, third); 167 case MSGRCV: 168 switch (version) { 169 case 0: { 170 struct ipc_kludge tmp; 171 if (!ptr) 172 return -EINVAL; 173 if (copy_from_user(&tmp,(struct ipc_kludge __user *)ptr, 174 sizeof (tmp))) 175 return -EFAULT; 176 return sys_msgrcv (first, tmp.msgp, second, 177 tmp.msgtyp, third); 178 } 179 default: 180 return sys_msgrcv (first, 181 (struct msgbuf __user *) ptr, 182 second, fifth, third); 183 } 184 case MSGGET: 185 return sys_msgget ((key_t) first, second); 186 case MSGCTL: 187 return sys_msgctl(first, second, (struct msqid_ds __user *)ptr); 188 189 case SHMAT: 190 switch (version) { 191 default: { 192 ulong raddr; 193 ret = do_shmat(first, (char __user *)ptr, second, &raddr); 194 if (ret) 195 return ret; 196 return put_user(raddr, (ulong __user *)third); 197 } 198 case 1: /* Of course, we don't support iBCS2! */ 199 return -EINVAL; 200 } 201 case SHMDT: 202 return sys_shmdt ((char __user *)ptr); 203 case SHMGET: 204 return sys_shmget (first, second, third); 205 case SHMCTL: 206 return sys_shmctl (first, second, 207 (struct shmid_ds __user *) ptr); 208 default: 209 return -ENOSYS; 210 } 211 } 212 #endif 213 214 /* Fork a new task - this creates a new program thread. 215 * This is called indirectly via a small wrapper 216 */ 217 asmlinkage int sys_fork(struct pt_regs *regs) 218 { 219 #ifdef CONFIG_MMU 220 return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); 221 #else 222 /* can not support in nommu mode */ 223 return(-EINVAL); 224 #endif 225 } 226 227 /* Clone a task - this clones the calling program thread. 228 * This is called indirectly via a small wrapper 229 */ 230 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, 231 int __user *parent_tidptr, int tls_val, 232 int __user *child_tidptr, struct pt_regs *regs) 233 { 234 if (!newsp) 235 newsp = regs->ARM_sp; 236 237 return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); 238 } 239 240 asmlinkage int sys_vfork(struct pt_regs *regs) 241 { 242 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); 243 } 244 245 /* sys_execve() executes a new program. 246 * This is called indirectly via a small wrapper 247 */ 248 asmlinkage int sys_execve(char __user *filenamei, char __user * __user *argv, 249 char __user * __user *envp, struct pt_regs *regs) 250 { 251 int error; 252 char * filename; 253 254 filename = getname(filenamei); 255 error = PTR_ERR(filename); 256 if (IS_ERR(filename)) 257 goto out; 258 error = do_execve(filename, argv, envp, regs); 259 putname(filename); 260 out: 261 return error; 262 } 263 264 int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 265 { 266 struct pt_regs regs; 267 int ret; 268 269 memset(®s, 0, sizeof(struct pt_regs)); 270 ret = do_execve((char *)filename, (char __user * __user *)argv, 271 (char __user * __user *)envp, ®s); 272 if (ret < 0) 273 goto out; 274 275 /* 276 * Save argc to the register structure for userspace. 277 */ 278 regs.ARM_r0 = ret; 279 280 /* 281 * We were successful. We won't be returning to our caller, but 282 * instead to user space by manipulating the kernel stack. 283 */ 284 asm( "add r0, %0, %1\n\t" 285 "mov r1, %2\n\t" 286 "mov r2, %3\n\t" 287 "bl memmove\n\t" /* copy regs to top of stack */ 288 "mov r8, #0\n\t" /* not a syscall */ 289 "mov r9, %0\n\t" /* thread structure */ 290 "mov sp, r0\n\t" /* reposition stack pointer */ 291 "b ret_to_user" 292 : 293 : "r" (current_thread_info()), 294 "Ir" (THREAD_START_SP - sizeof(regs)), 295 "r" (®s), 296 "Ir" (sizeof(regs)) 297 : "r0", "r1", "r2", "r3", "ip", "lr", "memory"); 298 299 out: 300 return ret; 301 } 302 EXPORT_SYMBOL(kernel_execve); 303 304 /* 305 * Since loff_t is a 64 bit type we avoid a lot of ABI hassle 306 * with a different argument ordering. 307 */ 308 asmlinkage long sys_arm_fadvise64_64(int fd, int advice, 309 loff_t offset, loff_t len) 310 { 311 return sys_fadvise64_64(fd, offset, len, advice); 312 } 313