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