1 /* 2 * Copyright (C) 2007-2009 Michal Simek <[email protected]> 3 * Copyright (C) 2007-2009 PetaLogix 4 * Copyright (C) 2007 John Williams <[email protected]> 5 * 6 * Copyright (C) 2006 Atmark Techno, Inc. 7 * Yasushi SHOJI <[email protected]> 8 * Tetsuya OHKAWA <[email protected]> 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file "COPYING" in the main directory of this archive 12 * for more details. 13 */ 14 15 #include <linux/errno.h> 16 #include <linux/mm.h> 17 #include <linux/smp.h> 18 #include <linux/smp_lock.h> 19 #include <linux/syscalls.h> 20 #include <linux/sem.h> 21 #include <linux/msg.h> 22 #include <linux/shm.h> 23 #include <linux/stat.h> 24 #include <linux/mman.h> 25 #include <linux/sys.h> 26 #include <linux/ipc.h> 27 #include <linux/utsname.h> 28 #include <linux/file.h> 29 #include <linux/module.h> 30 #include <linux/err.h> 31 #include <linux/fs.h> 32 #include <linux/ipc.h> 33 #include <linux/semaphore.h> 34 #include <linux/syscalls.h> 35 #include <linux/uaccess.h> 36 #include <linux/unistd.h> 37 38 #include <asm/syscalls.h> 39 /* 40 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 41 * 42 * This is really horribly ugly. This will be remove with new toolchain. 43 */ 44 asmlinkage int 45 sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth) 46 { 47 int version, ret; 48 49 version = call >> 16; /* hack for backward compatibility */ 50 call &= 0xffff; 51 52 ret = -EINVAL; 53 switch (call) { 54 case SEMOP: 55 ret = sys_semop(first, (struct sembuf *)ptr, second); 56 break; 57 case SEMGET: 58 ret = sys_semget(first, second, third); 59 break; 60 case SEMCTL: 61 { 62 union semun fourth; 63 64 if (!ptr) 65 break; 66 ret = (access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT) 67 || (get_user(fourth.__pad, (void **)ptr)) ; 68 if (ret) 69 break; 70 ret = sys_semctl(first, second, third, fourth); 71 break; 72 } 73 case MSGSND: 74 ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third); 75 break; 76 case MSGRCV: 77 switch (version) { 78 case 0: { 79 struct ipc_kludge tmp; 80 81 if (!ptr) 82 break; 83 ret = (access_ok(VERIFY_READ, ptr, sizeof(tmp)) 84 ? 0 : -EFAULT) || copy_from_user(&tmp, 85 (struct ipc_kludge *) ptr, sizeof(tmp)); 86 if (ret) 87 break; 88 ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp, 89 third); 90 break; 91 } 92 default: 93 ret = sys_msgrcv(first, (struct msgbuf *) ptr, 94 second, fifth, third); 95 break; 96 } 97 break; 98 case MSGGET: 99 ret = sys_msgget((key_t) first, second); 100 break; 101 case MSGCTL: 102 ret = sys_msgctl(first, second, (struct msqid_ds *) ptr); 103 break; 104 case SHMAT: 105 switch (version) { 106 default: { 107 ulong raddr; 108 ret = access_ok(VERIFY_WRITE, (ulong *) third, 109 sizeof(ulong)) ? 0 : -EFAULT; 110 if (ret) 111 break; 112 ret = do_shmat(first, (char *) ptr, second, &raddr); 113 if (ret) 114 break; 115 ret = put_user(raddr, (ulong *) third); 116 break; 117 } 118 case 1: /* iBCS2 emulator entry point */ 119 if (!segment_eq(get_fs(), get_ds())) 120 break; 121 ret = do_shmat(first, (char *) ptr, second, 122 (ulong *) third); 123 break; 124 } 125 break; 126 case SHMDT: 127 ret = sys_shmdt((char *)ptr); 128 break; 129 case SHMGET: 130 ret = sys_shmget(first, second, third); 131 break; 132 case SHMCTL: 133 ret = sys_shmctl(first, second, (struct shmid_ds *) ptr); 134 break; 135 } 136 return -EINVAL; 137 } 138 139 asmlinkage int sys_vfork(struct pt_regs *regs) 140 { 141 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1, 142 regs, 0, NULL, NULL); 143 } 144 145 asmlinkage int sys_clone(int flags, unsigned long stack, struct pt_regs *regs) 146 { 147 if (!stack) 148 stack = regs->r1; 149 return do_fork(flags, stack, regs, 0, NULL, NULL); 150 } 151 152 asmlinkage int sys_execve(char __user *filenamei, char __user *__user *argv, 153 char __user *__user *envp, struct pt_regs *regs) 154 { 155 int error; 156 char *filename; 157 158 filename = getname(filenamei); 159 error = PTR_ERR(filename); 160 if (IS_ERR(filename)) 161 goto out; 162 error = do_execve(filename, argv, envp, regs); 163 putname(filename); 164 out: 165 return error; 166 } 167 168 asmlinkage unsigned long 169 sys_mmap2(unsigned long addr, size_t len, 170 unsigned long prot, unsigned long flags, 171 unsigned long fd, unsigned long pgoff) 172 { 173 struct file *file = NULL; 174 int ret = -EBADF; 175 176 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 177 if (!(flags & MAP_ANONYMOUS)) { 178 file = fget(fd); 179 if (!file) { 180 printk(KERN_INFO "no fd in mmap\r\n"); 181 goto out; 182 } 183 } 184 185 down_write(¤t->mm->mmap_sem); 186 ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 187 up_write(¤t->mm->mmap_sem); 188 if (file) 189 fput(file); 190 out: 191 return ret; 192 } 193 194 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, 195 unsigned long prot, unsigned long flags, 196 unsigned long fd, off_t offset) 197 { 198 int err = -EINVAL; 199 200 if (offset & ~PAGE_MASK) { 201 printk(KERN_INFO "no pagemask in mmap\r\n"); 202 goto out; 203 } 204 205 err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); 206 out: 207 return err; 208 } 209 210 /* 211 * Do a system call from kernel instead of calling sys_execve so we 212 * end up with proper pt_regs. 213 */ 214 int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 215 { 216 register const char *__a __asm__("r5") = filename; 217 register const void *__b __asm__("r6") = argv; 218 register const void *__c __asm__("r7") = envp; 219 register unsigned long __syscall __asm__("r12") = __NR_execve; 220 register unsigned long __ret __asm__("r3"); 221 __asm__ __volatile__ ("brki r14, 0x8" 222 : "=r" (__ret), "=r" (__syscall) 223 : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) 224 : "r4", "r8", "r9", 225 "r10", "r11", "r14", "cc", "memory"); 226 return __ret; 227 } 228