patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ppc64 / kernel / syscalls.c
1 /*
2  * linux/arch/ppc64/kernel/sys_ppc.c
3  *
4  *  PowerPC version 
5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6  *
7  * Derived from "arch/i386/kernel/sys_i386.c"
8  * Adapted from the i386 version by Gary Thomas
9  * Modified by Cort Dougan (cort@cs.nmt.edu)
10  * and Paul Mackerras (paulus@cs.anu.edu.au).
11  *
12  * This file contains various random system calls that
13  * have a non-standard calling sequence on the Linux/PPC
14  * platform.
15  *
16  *  This program is free software; you can redistribute it and/or
17  *  modify it under the terms of the GNU General Public License
18  *  as published by the Free Software Foundation; either version
19  *  2 of the License, or (at your option) any later version.
20  *
21  */
22
23 #include <linux/errno.h>
24 #include <linux/sched.h>
25 #include <linux/syscalls.h>
26 #include <linux/mm.h>
27 #include <linux/smp.h>
28 #include <linux/smp_lock.h>
29 #include <linux/sem.h>
30 #include <linux/msg.h>
31 #include <linux/shm.h>
32 #include <linux/stat.h>
33 #include <linux/mman.h>
34 #include <linux/sys.h>
35 #include <linux/ipc.h>
36 #include <linux/utsname.h>
37 #include <linux/file.h>
38 #include <linux/init.h>
39 #include <linux/personality.h>
40
41 #include <asm/uaccess.h>
42 #include <asm/ipc.h>
43 #include <asm/semaphore.h>
44 #include <asm/time.h>
45 #include <asm/unistd.h>
46
47 extern unsigned long wall_jiffies;
48
49 void
50 check_bugs(void)
51 {
52 }
53
54 /*
55  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
56  *
57  * This is really horribly ugly.
58  */
59 asmlinkage int 
60 sys_ipc (uint call, int first, int second, long third, void __user *ptr, long fifth)
61 {
62         int version, ret;
63
64         version = call >> 16; /* hack for backward compatibility */
65         call &= 0xffff;
66
67         ret = -ENOSYS;
68         switch (call) {
69         case SEMOP:
70                 ret = sys_semtimedop (first, (struct sembuf __user *)ptr, second,
71                                       NULL);
72                 break;
73         case SEMTIMEDOP:
74                 ret = sys_semtimedop (first, (struct sembuf __user *)ptr, second,
75                                       (const struct timespec __user *) fifth);
76                 break;
77         case SEMGET:
78                 ret = sys_semget (first, second, third);
79                 break;
80         case SEMCTL: {
81                 union semun fourth;
82
83                 ret = -EINVAL;
84                 if (!ptr)
85                         break;
86                 if ((ret = get_user(fourth.__pad, (void __user * __user *)ptr)))
87                         break;
88                 ret = sys_semctl (first, second, third, fourth);
89                 break;
90         }
91         case MSGSND:
92                 ret = sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third);
93                 break;
94         case MSGRCV:
95                 switch (version) {
96                 case 0: {
97                         struct ipc_kludge tmp;
98
99                         ret = -EINVAL;
100                         if (!ptr)
101                                 break;
102                         if ((ret = copy_from_user(&tmp,
103                                                 (struct ipc_kludge __user *) ptr,
104                                                 sizeof (tmp)) ? -EFAULT : 0))
105                                 break;
106                         ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
107                                           third);
108                         break;
109                 }
110                 default:
111                         ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
112                                           second, fifth, third);
113                         break;
114                 }
115                 break;
116         case MSGGET:
117                 ret = sys_msgget ((key_t) first, second);
118                 break;
119         case MSGCTL:
120                 ret = sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
121                 break;
122         case SHMAT:
123                 switch (version) {
124                 default: {
125                         ulong raddr;
126                         ret = do_shmat (first, (char __user *) ptr, second, &raddr);
127                         if (ret)
128                                 break;
129                         ret = put_user (raddr, (ulong __user *) third);
130                         break;
131                 }
132                 case 1: /* iBCS2 emulator entry point */
133                         ret = -EINVAL;
134                         if (!segment_eq(get_fs(), get_ds()))
135                                 break;
136                         ret = do_shmat (first, (char __user *) ptr, second,
137                                          (ulong *) third);
138                         break;
139                 }
140                 break;
141         case SHMDT: 
142                 ret = sys_shmdt ((char __user *)ptr);
143                 break;
144         case SHMGET:
145                 ret = sys_shmget (first, second, third);
146                 break;
147         case SHMCTL:
148                 ret = sys_shmctl (first, second, (struct shmid_ds __user *) ptr);
149                 break;
150         }
151
152         return ret;
153 }
154
155 /*
156  * sys_pipe() is the normal C calling standard for creating
157  * a pipe. It's not the way unix traditionally does this, though.
158  */
159 asmlinkage int sys_pipe(int __user *fildes)
160 {
161         int fd[2];
162         int error;
163         
164         error = do_pipe(fd);
165         if (!error) {
166                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
167                         error = -EFAULT;
168         }
169         
170         return error;
171 }
172
173 unsigned long sys_mmap(unsigned long addr, size_t len,
174                        unsigned long prot, unsigned long flags,
175                        unsigned long fd, off_t offset)
176 {
177         struct file * file = NULL;
178         unsigned long ret = -EBADF;
179
180         if (!(flags & MAP_ANONYMOUS)) {
181                 if (!(file = fget(fd)))
182                         goto out;
183         }
184
185         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
186         down_write(&current->mm->mmap_sem);
187         ret = do_mmap(file, addr, len, prot, flags, offset);
188         up_write(&current->mm->mmap_sem);
189         if (file)
190                 fput(file);
191
192 out:
193         return ret;
194 }
195
196 static int __init set_fakeppc(char *str)
197 {
198         if (*str)
199                 return 0;
200         init_task.personality = PER_LINUX32;
201         return 1;
202 }
203 __setup("fakeppc", set_fakeppc);
204
205 asmlinkage int sys_uname(struct old_utsname __user * name)
206 {
207         int err = -EFAULT;
208         
209         down_read(&uts_sem);
210         if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
211                 err = 0;
212         up_read(&uts_sem);
213         
214         return err;
215 }
216
217 asmlinkage time_t sys64_time(time_t __user * tloc)
218 {
219         time_t secs;
220         time_t usecs;
221
222         long tb_delta = tb_ticks_since(tb_last_stamp);
223         tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
224
225         secs  = xtime.tv_sec;  
226         usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec;
227         while (usecs >= USEC_PER_SEC) {
228                 ++secs;
229                 usecs -= USEC_PER_SEC;
230         }
231
232         if (tloc) {
233                 if (put_user(secs,tloc))
234                         secs = -EFAULT;
235         }
236
237         return secs;
238 }
239
240 /* Only exists on P-series. */
241 cond_syscall(ppc_rtas);