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/ipc.h> 29 #include <linux/uaccess.h> 30 31 struct mmap_arg_struct { 32 unsigned long addr; 33 unsigned long len; 34 unsigned long prot; 35 unsigned long flags; 36 unsigned long fd; 37 unsigned long offset; 38 }; 39 40 asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) 41 { 42 int error = -EFAULT; 43 struct mmap_arg_struct a; 44 45 if (copy_from_user(&a, arg, sizeof(a))) 46 goto out; 47 48 error = -EINVAL; 49 if (a.offset & ~PAGE_MASK) 50 goto out; 51 52 error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); 53 out: 54 return error; 55 } 56 57 /* 58 * Perform the select(nd, in, out, ex, tv) and mmap() system 59 * calls. 60 */ 61 62 struct sel_arg_struct { 63 unsigned long n; 64 fd_set __user *inp, *outp, *exp; 65 struct timeval __user *tvp; 66 }; 67 68 asmlinkage int old_select(struct sel_arg_struct __user *arg) 69 { 70 struct sel_arg_struct a; 71 72 if (copy_from_user(&a, arg, sizeof(a))) 73 return -EFAULT; 74 /* sys_select() does the appropriate kernel locking */ 75 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); 76 } 77 78 #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) 79 /* 80 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 81 * 82 * This is really horribly ugly. 83 */ 84 asmlinkage int sys_ipc(uint call, int first, int second, int third, 85 void __user *ptr, long fifth) 86 { 87 int version, ret; 88 89 version = call >> 16; /* hack for backward compatibility */ 90 call &= 0xffff; 91 92 switch (call) { 93 case SEMOP: 94 return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); 95 case SEMTIMEDOP: 96 return sys_semtimedop(first, (struct sembuf __user *)ptr, second, 97 (const struct timespec __user *)fifth); 98 99 case SEMGET: 100 return sys_semget (first, second, third); 101 case SEMCTL: { 102 union semun fourth; 103 if (!ptr) 104 return -EINVAL; 105 if (get_user(fourth.__pad, (void __user * __user *) ptr)) 106 return -EFAULT; 107 return sys_semctl (first, second, third, fourth); 108 } 109 110 case MSGSND: 111 return sys_msgsnd(first, (struct msgbuf __user *) ptr, 112 second, third); 113 case MSGRCV: 114 switch (version) { 115 case 0: { 116 struct ipc_kludge tmp; 117 if (!ptr) 118 return -EINVAL; 119 if (copy_from_user(&tmp,(struct ipc_kludge __user *)ptr, 120 sizeof (tmp))) 121 return -EFAULT; 122 return sys_msgrcv (first, tmp.msgp, second, 123 tmp.msgtyp, third); 124 } 125 default: 126 return sys_msgrcv (first, 127 (struct msgbuf __user *) ptr, 128 second, fifth, third); 129 } 130 case MSGGET: 131 return sys_msgget ((key_t) first, second); 132 case MSGCTL: 133 return sys_msgctl(first, second, (struct msqid_ds __user *)ptr); 134 135 case SHMAT: 136 switch (version) { 137 default: { 138 ulong raddr; 139 ret = do_shmat(first, (char __user *)ptr, second, &raddr); 140 if (ret) 141 return ret; 142 return put_user(raddr, (ulong __user *)third); 143 } 144 case 1: /* Of course, we don't support iBCS2! */ 145 return -EINVAL; 146 } 147 case SHMDT: 148 return sys_shmdt ((char __user *)ptr); 149 case SHMGET: 150 return sys_shmget (first, second, third); 151 case SHMCTL: 152 return sys_shmctl (first, second, 153 (struct shmid_ds __user *) ptr); 154 default: 155 return -ENOSYS; 156 } 157 } 158 #endif 159 160 /* Fork a new task - this creates a new program thread. 161 * This is called indirectly via a small wrapper 162 */ 163 asmlinkage int sys_fork(struct pt_regs *regs) 164 { 165 #ifdef CONFIG_MMU 166 return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); 167 #else 168 /* can not support in nommu mode */ 169 return(-EINVAL); 170 #endif 171 } 172 173 /* Clone a task - this clones the calling program thread. 174 * This is called indirectly via a small wrapper 175 */ 176 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, 177 int __user *parent_tidptr, int tls_val, 178 int __user *child_tidptr, struct pt_regs *regs) 179 { 180 if (!newsp) 181 newsp = regs->ARM_sp; 182 183 return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); 184 } 185 186 asmlinkage int sys_vfork(struct pt_regs *regs) 187 { 188 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); 189 } 190 191 /* sys_execve() executes a new program. 192 * This is called indirectly via a small wrapper 193 */ 194 asmlinkage int sys_execve(char __user *filenamei, char __user * __user *argv, 195 char __user * __user *envp, struct pt_regs *regs) 196 { 197 int error; 198 char * filename; 199 200 filename = getname(filenamei); 201 error = PTR_ERR(filename); 202 if (IS_ERR(filename)) 203 goto out; 204 error = do_execve(filename, argv, envp, regs); 205 putname(filename); 206 out: 207 return error; 208 } 209 210 int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 211 { 212 struct pt_regs regs; 213 int ret; 214 215 memset(®s, 0, sizeof(struct pt_regs)); 216 ret = do_execve((char *)filename, (char __user * __user *)argv, 217 (char __user * __user *)envp, ®s); 218 if (ret < 0) 219 goto out; 220 221 /* 222 * Save argc to the register structure for userspace. 223 */ 224 regs.ARM_r0 = ret; 225 226 /* 227 * We were successful. We won't be returning to our caller, but 228 * instead to user space by manipulating the kernel stack. 229 */ 230 asm( "add r0, %0, %1\n\t" 231 "mov r1, %2\n\t" 232 "mov r2, %3\n\t" 233 "bl memmove\n\t" /* copy regs to top of stack */ 234 "mov r8, #0\n\t" /* not a syscall */ 235 "mov r9, %0\n\t" /* thread structure */ 236 "mov sp, r0\n\t" /* reposition stack pointer */ 237 "b ret_to_user" 238 : 239 : "r" (current_thread_info()), 240 "Ir" (THREAD_START_SP - sizeof(regs)), 241 "r" (®s), 242 "Ir" (sizeof(regs)) 243 : "r0", "r1", "r2", "r3", "ip", "lr", "memory"); 244 245 out: 246 return ret; 247 } 248 EXPORT_SYMBOL(kernel_execve); 249 250 /* 251 * Since loff_t is a 64 bit type we avoid a lot of ABI hassle 252 * with a different argument ordering. 253 */ 254 asmlinkage long sys_arm_fadvise64_64(int fd, int advice, 255 loff_t offset, loff_t len) 256 { 257 return sys_fadvise64_64(fd, offset, len, advice); 258 } 259