]> git.karo-electronics.de Git - mv-sheeva.git/blob - arch/microblaze/kernel/sys_microblaze.c
d90b548fb1bbe6f1d5d101f8fa16d5c1af30b2b2
[mv-sheeva.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/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(&current->mm->mmap_sem);
186         ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
187         up_write(&current->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 }