Merge branch 'for-rmk' of git://git.marvell.com/orion
[pandora-kernel.git] / arch / microblaze / kernel / sys_microblaze.c
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 long
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 ret;
135 }
136
137 asmlinkage long microblaze_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 long microblaze_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 long microblaze_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 long
167 sys_mmap2(unsigned long addr, unsigned long 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(&current->mm->mmap_sem);
184         ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
185         up_write(&current->mm->mmap_sem);
186         if (file)
187                 fput(file);
188 out:
189         return ret;
190 }
191
192 asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
193                         unsigned long prot, unsigned long flags,
194                         unsigned long fd, off_t pgoff)
195 {
196         int err = -EINVAL;
197
198         if (pgoff & ~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, pgoff >> 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 }