File: /usr/src/linux/arch/ppc/kernel/syscalls.c
1 /*
2 * BK Id: SCCS/s.syscalls.c 1.8 05/17/01 18:14:22 cort
3 */
4 /*
5 * linux/arch/ppc/kernel/sys_ppc.c
6 *
7 * PowerPC version
8 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
9 *
10 * Derived from "arch/i386/kernel/sys_i386.c"
11 * Adapted from the i386 version by Gary Thomas
12 * Modified by Cort Dougan (cort@cs.nmt.edu)
13 * and Paul Mackerras (paulus@cs.anu.edu.au).
14 *
15 * This file contains various random system calls that
16 * have a non-standard calling sequence on the Linux/PPC
17 * platform.
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 *
24 */
25
26 #include <linux/config.h>
27 #include <linux/errno.h>
28 #include <linux/sched.h>
29 #include <linux/mm.h>
30 #include <linux/smp.h>
31 #include <linux/smp_lock.h>
32 #include <linux/sem.h>
33 #include <linux/msg.h>
34 #include <linux/shm.h>
35 #include <linux/stat.h>
36 #include <linux/mman.h>
37 #include <linux/sys.h>
38 #include <linux/ipc.h>
39 #include <linux/utsname.h>
40 #include <linux/file.h>
41
42 #include <asm/uaccess.h>
43 #include <asm/ipc.h>
44 #include <asm/semaphore.h>
45
46 void
47 check_bugs(void)
48 {
49 }
50
51 int sys_ioperm(unsigned long from, unsigned long num, int on)
52 {
53 printk(KERN_ERR "sys_ioperm()\n");
54 return -EIO;
55 }
56
57 int sys_iopl(int a1, int a2, int a3, int a4)
58 {
59 printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
60 return (-ENOSYS);
61 }
62
63 int sys_vm86(int a1, int a2, int a3, int a4)
64 {
65 printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
66 return (-ENOSYS);
67 }
68
69 int sys_modify_ldt(int a1, int a2, int a3, int a4)
70 {
71 printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
72 return (-ENOSYS);
73 }
74
75 /*
76 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
77 *
78 * This is really horribly ugly.
79 */
80 int
81 sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
82 {
83 int version, ret;
84
85 version = call >> 16; /* hack for backward compatibility */
86 call &= 0xffff;
87
88 ret = -EINVAL;
89 switch (call) {
90 case SEMOP:
91 ret = sys_semop (first, (struct sembuf *)ptr, second);
92 break;
93 case SEMGET:
94 ret = sys_semget (first, second, third);
95 break;
96 case SEMCTL: {
97 union semun fourth;
98
99 if (!ptr)
100 break;
101 if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
102 || (ret = get_user(fourth.__pad, (void **)ptr)))
103 break;
104 ret = sys_semctl (first, second, third, fourth);
105 break;
106 }
107 case MSGSND:
108 ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
109 break;
110 case MSGRCV:
111 switch (version) {
112 case 0: {
113 struct ipc_kludge tmp;
114
115 if (!ptr)
116 break;
117 if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
118 || (ret = copy_from_user(&tmp,
119 (struct ipc_kludge *) ptr,
120 sizeof (tmp))))
121 break;
122 ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
123 third);
124 break;
125 }
126 default:
127 ret = sys_msgrcv (first, (struct msgbuf *) ptr,
128 second, fifth, third);
129 break;
130 }
131 break;
132 case MSGGET:
133 ret = sys_msgget ((key_t) first, second);
134 break;
135 case MSGCTL:
136 ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
137 break;
138 case SHMAT:
139 switch (version) {
140 default: {
141 ulong raddr;
142
143 if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
144 sizeof(ulong))))
145 break;
146 ret = sys_shmat (first, (char *) ptr, second, &raddr);
147 if (ret)
148 break;
149 ret = put_user (raddr, (ulong *) third);
150 break;
151 }
152 case 1: /* iBCS2 emulator entry point */
153 if (!segment_eq(get_fs(), get_ds()))
154 break;
155 ret = sys_shmat (first, (char *) ptr, second,
156 (ulong *) third);
157 break;
158 }
159 break;
160 case SHMDT:
161 ret = sys_shmdt ((char *)ptr);
162 break;
163 case SHMGET:
164 ret = sys_shmget (first, second, third);
165 break;
166 case SHMCTL:
167 ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
168 break;
169 }
170
171 return ret;
172 }
173
174 /*
175 * sys_pipe() is the normal C calling standard for creating
176 * a pipe. It's not the way unix traditionally does this, though.
177 */
178 int sys_pipe(int *fildes)
179 {
180 int fd[2];
181 int error;
182
183 error = do_pipe(fd);
184 if (!error) {
185 if (copy_to_user(fildes, fd, 2*sizeof(int)))
186 error = -EFAULT;
187 }
188 return error;
189 }
190
191 static inline unsigned long
192 do_mmap2(unsigned long addr, size_t len,
193 unsigned long prot, unsigned long flags,
194 unsigned long fd, unsigned long pgoff)
195 {
196 struct file * file = NULL;
197 int ret = -EBADF;
198
199 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
200 if (!(flags & MAP_ANONYMOUS)) {
201 if (!(file = fget(fd)))
202 goto out;
203 }
204
205 down_write(¤t->mm->mmap_sem);
206 ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
207 up_write(¤t->mm->mmap_sem);
208 if (file)
209 fput(file);
210 out:
211 return ret;
212 }
213
214 unsigned long sys_mmap2(unsigned long addr, size_t len,
215 unsigned long prot, unsigned long flags,
216 unsigned long fd, unsigned long pgoff)
217 {
218 return do_mmap2(addr, len, prot, flags, fd, pgoff);
219 }
220
221 unsigned long sys_mmap(unsigned long addr, size_t len,
222 unsigned long prot, unsigned long flags,
223 unsigned long fd, off_t offset)
224 {
225 int err = -EINVAL;
226
227 if (offset & ~PAGE_MASK)
228 goto out;
229
230 err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
231 out:
232 return err;
233 }
234
235 extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
236
237 /*
238 * Due to some executables calling the wrong select we sometimes
239 * get wrong args. This determines how the args are being passed
240 * (a single ptr to them all args passed) then calls
241 * sys_select() with the appropriate args. -- Cort
242 */
243 int
244 ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
245 {
246 if ( (unsigned long)n >= 4096 )
247 {
248 unsigned long *buffer = (unsigned long *)n;
249 if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
250 || __get_user(n, buffer)
251 || __get_user(inp, ((fd_set **)(buffer+1)))
252 || __get_user(outp, ((fd_set **)(buffer+2)))
253 || __get_user(exp, ((fd_set **)(buffer+3)))
254 || __get_user(tvp, ((struct timeval **)(buffer+4))))
255 return -EFAULT;
256 }
257 return sys_select(n, inp, outp, exp, tvp);
258 }
259
260 int sys_pause(void)
261 {
262 current->state = TASK_INTERRUPTIBLE;
263 schedule();
264 return -ERESTARTNOHAND;
265 }
266
267 int sys_uname(struct old_utsname * name)
268 {
269 int err = -EFAULT;
270
271 down_read(&uts_sem);
272 if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
273 err = 0;
274 up_read(&uts_sem);
275 return err;
276 }
277
278 int sys_olduname(struct oldold_utsname * name)
279 {
280 int error;
281
282 if (!name)
283 return -EFAULT;
284 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
285 return -EFAULT;
286
287 down_read(&uts_sem);
288 error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
289 error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
290 error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
291 error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
292 error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
293 error -= __put_user(0,name->release+__OLD_UTS_LEN);
294 error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
295 error -= __put_user(0,name->version+__OLD_UTS_LEN);
296 error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
297 error = __put_user(0,name->machine+__OLD_UTS_LEN);
298 up_read(&uts_sem);
299
300 error = error ? -EFAULT : 0;
301 return error;
302 }
303
304 #ifndef CONFIG_PCI
305 /*
306 * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
307 * not defined, this file is not linked at all, so here are the "empty" versions
308 */
309 asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
310 asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
311 asmlinkage long sys_pciconfig_iobase() { return -ENOSYS; }
312 #endif
313