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