Import 2.3.6
[davej-history.git] / arch / arm / kernel / sys_arm.c
blobd50b90f8d6812a91e85c177ef55c25af4e150de5
1 /*
2 * linux/arch/arm/kernel/sys_arm.c
4 * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c
5 * Copyright (C) 1995, 1996 Russell King.
6 *
7 * This file contains various random system calls that
8 * have a non-standard calling sequence on the Linux/arm
9 * platform.
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/sem.h>
18 #include <linux/msg.h>
19 #include <linux/shm.h>
20 #include <linux/stat.h>
21 #include <linux/mman.h>
22 #include <linux/file.h>
23 #include <linux/utsname.h>
25 #include <asm/uaccess.h>
26 #include <asm/ipc.h>
29 * Constant strings used in inlined functions in header files
31 /* proc/system.h */
32 const char xchg_str[] = "xchg";
35 * sys_pipe() is the normal C calling standard for creating
36 * a pipe. It's not the way unix traditionally does this, though.
38 asmlinkage int sys_pipe(unsigned long * fildes)
40 int fd[2];
41 int error;
43 lock_kernel();
44 error = do_pipe(fd);
45 unlock_kernel();
46 if (!error) {
47 if (copy_to_user(fildes, fd, 2*sizeof(int)))
48 error = -EFAULT;
50 return error;
54 * Perform the select(nd, in, out, ex, tv) and mmap() system
55 * calls. ARM Linux didn't use to be able to handle more than
56 * 4 system call parameters, so these system calls used a memory
57 * block for parameter passing..
60 struct mmap_arg_struct {
61 unsigned long addr;
62 unsigned long len;
63 unsigned long prot;
64 unsigned long flags;
65 unsigned long fd;
66 unsigned long offset;
69 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
71 int error = -EFAULT;
72 struct file * file = NULL;
73 struct mmap_arg_struct a;
75 lock_kernel();
76 if (copy_from_user(&a, arg, sizeof(a)))
77 goto out;
78 if (!(a.flags & MAP_ANONYMOUS)) {
79 error = -EBADF;
80 file = fget(a.fd);
81 if (!file)
82 goto out;
84 a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
85 error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
86 if (file)
87 fput(file);
88 out:
89 unlock_kernel();
90 return error;
94 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
96 struct sel_arg_struct {
97 unsigned long n;
98 fd_set *inp, *outp, *exp;
99 struct timeval *tvp;
102 asmlinkage int old_select(struct sel_arg_struct *arg)
104 struct sel_arg_struct a;
106 if (copy_from_user(&a, arg, sizeof(a)))
107 return -EFAULT;
108 /* sys_select() does the appropriate kernel locking */
109 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
113 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
115 * This is really horribly ugly.
117 asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
119 int version, ret;
121 lock_kernel();
122 version = call >> 16; /* hack for backward compatibility */
123 call &= 0xffff;
125 if (call <= SEMCTL)
126 switch (call) {
127 case SEMOP:
128 ret = sys_semop (first, (struct sembuf *)ptr, second);
129 goto out;
130 case SEMGET:
131 ret = sys_semget (first, second, third);
132 goto out;
133 case SEMCTL: {
134 union semun fourth;
135 ret = -EINVAL;
136 if (!ptr)
137 goto out;
138 ret = -EFAULT;
139 if (get_user(fourth.__pad, (void **) ptr))
140 goto out;
141 ret = sys_semctl (first, second, third, fourth);
142 goto out;
144 default:
145 ret = -EINVAL;
146 goto out;
148 if (call <= MSGCTL)
149 switch (call) {
150 case MSGSND:
151 ret = sys_msgsnd (first, (struct msgbuf *) ptr,
152 second, third);
153 goto out;
154 case MSGRCV:
155 switch (version) {
156 case 0: {
157 struct ipc_kludge tmp;
158 ret = -EINVAL;
159 if (!ptr)
160 goto out;
161 ret = -EFAULT;
162 if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
163 sizeof (tmp)))
164 goto out;
165 ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
166 goto out;
168 case 1: default:
169 ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
170 goto out;
172 case MSGGET:
173 ret = sys_msgget ((key_t) first, second);
174 goto out;
175 case MSGCTL:
176 ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
177 goto out;
178 default:
179 ret = -EINVAL;
180 goto out;
182 if (call <= SHMCTL)
183 switch (call) {
184 case SHMAT:
185 switch (version) {
186 case 0: default: {
187 ulong raddr;
188 ret = sys_shmat (first, (char *) ptr, second, &raddr);
189 if (ret)
190 goto out;
191 ret = put_user (raddr, (ulong *) third);
192 goto out;
194 case 1: /* iBCS2 emulator entry point */
195 ret = -EINVAL;
196 if (!segment_eq(get_fs(), get_ds()))
197 goto out;
198 ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
199 goto out;
201 case SHMDT:
202 ret = sys_shmdt ((char *)ptr);
203 goto out;
204 case SHMGET:
205 ret = sys_shmget (first, second, third);
206 goto out;
207 case SHMCTL:
208 ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
209 goto out;
210 default:
211 ret = -EINVAL;
212 goto out;
214 else
215 ret = -EINVAL;
216 out:
217 unlock_kernel();
218 return ret;
221 /* Fork a new task - this creates a new program thread.
222 * This is called indirectly via a small wrapper
224 asmlinkage int sys_fork(struct pt_regs *regs)
226 int ret;
228 lock_kernel();
229 ret = do_fork(SIGCHLD, regs->ARM_sp, regs);
230 unlock_kernel();
232 return ret;
235 /* Clone a task - this clones the calling program thread.
236 * This is called indirectly via a small wrapper
238 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
240 int ret;
242 lock_kernel();
243 if (!newsp)
244 newsp = regs->ARM_sp;
245 ret = do_fork(clone_flags, newsp, regs);
246 unlock_kernel();
247 return ret;
250 /* sys_execve() executes a new program.
251 * This is called indirectly via a small wrapper
253 asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_regs *regs)
255 int error;
256 char * filename;
258 lock_kernel();
259 filename = getname(filenamei);
260 error = PTR_ERR(filename);
261 if (IS_ERR(filename))
262 goto out;
263 error = do_execve(filename, argv, envp, regs);
264 putname(filename);
265 out:
266 unlock_kernel();
267 return error;
271 * Detect the old function calling standard
273 static inline unsigned long old_calling_standard (struct pt_regs *regs)
275 unsigned long instr, *pcv = (unsigned long *)(instruction_pointer(regs) - 8);
276 return (!get_user (instr, pcv) && instr == 0xe1a0300d);
279 /* Compatability functions - we used to pass 5 parameters as r0, r1, r2, *r3, *(r3+4)
280 * We now use r0 - r4, and return an error if the old style calling standard is used.
281 * Eventually these functions will disappear.
283 asmlinkage int
284 sys_compat_llseek (unsigned int fd, unsigned long offset_high, unsigned long offset_low,
285 loff_t *result, unsigned int origin, struct pt_regs *regs)
287 extern int sys_llseek (unsigned int, unsigned long, unsigned long, loff_t *, unsigned int);
289 if (old_calling_standard (regs)) {
290 printk (KERN_NOTICE "%s (%d): unsupported llseek call standard\n",
291 current->comm, current->pid);
292 return -EINVAL;
294 return sys_llseek (fd, offset_high, offset_low, result, origin);
297 asmlinkage int
298 sys_compat_mount (char *devname, char *dirname, char *type, unsigned long flags, void *data,
299 struct pt_regs *regs)
301 extern int sys_mount (char *, char *, char *, unsigned long, void *);
303 if (old_calling_standard (regs)) {
304 printk (KERN_NOTICE "%s (%d): unsupported mount call standard\n",
305 current->comm, current->pid);
306 return -EINVAL;
308 return sys_mount (devname, dirname, type, flags, data);
311 asmlinkage int sys_uname (struct old_utsname * name)
313 static int warned = 0;
314 int err;
316 if (warned == 0) {
317 warned ++;
318 printk (KERN_NOTICE "%s (%d): obsolete uname call\n",
319 current->comm, current->pid);
322 if(!name)
323 return -EFAULT;
324 down(&uts_sem);
325 err=copy_to_user (name, &system_utsname, sizeof (*name));
326 up(&uts_sem);
327 return err?-EFAULT:0;
330 asmlinkage int sys_olduname(struct oldold_utsname * name)
332 int error;
333 static int warned = 0;
335 if (warned == 0) {
336 warned ++;
337 printk (KERN_NOTICE "%s (%d): obsolete olduname call\n",
338 current->comm, current->pid);
341 if (!name)
342 return -EFAULT;
344 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
345 return -EFAULT;
347 down(&uts_sem);
349 error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
350 error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
351 error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
352 error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
353 error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
354 error -= __put_user(0,name->release+__OLD_UTS_LEN);
355 error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
356 error -= __put_user(0,name->version+__OLD_UTS_LEN);
357 error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
358 error -= __put_user(0,name->machine+__OLD_UTS_LEN);
360 up(&uts_sem);
362 error = error ? -EFAULT : 0;
364 return error;
367 asmlinkage int sys_pause(void)
369 current->state = TASK_INTERRUPTIBLE;
370 schedule();
371 return -ERESTARTNOHAND;