Pull button into test branch
[pandora-kernel.git] / arch / sh / kernel / sys_sh.c
1 /*
2  * linux/arch/sh/kernel/sys_sh.c
3  *
4  * This file contains various random system calls that
5  * have a non-standard calling sequence on the Linux/SuperH
6  * platform.
7  *
8  * Taken from i386 version.
9  */
10
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/mm.h>
14 #include <linux/smp.h>
15 #include <linux/smp_lock.h>
16 #include <linux/sem.h>
17 #include <linux/msg.h>
18 #include <linux/shm.h>
19 #include <linux/stat.h>
20 #include <linux/syscalls.h>
21 #include <linux/mman.h>
22 #include <linux/file.h>
23 #include <linux/utsname.h>
24 #include <linux/module.h>
25 #include <asm/cacheflush.h>
26 #include <asm/uaccess.h>
27 #include <asm/ipc.h>
28 #include <asm/unistd.h>
29
30 /*
31  * sys_pipe() is the normal C calling standard for creating
32  * a pipe. It's not the way Unix traditionally does this, though.
33  */
34 asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
35         unsigned long r6, unsigned long r7,
36         struct pt_regs __regs)
37 {
38         struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
39         int fd[2];
40         int error;
41
42         error = do_pipe(fd);
43         if (!error) {
44                 regs->regs[1] = fd[1];
45                 return fd[0];
46         }
47         return error;
48 }
49
50 unsigned long shm_align_mask = PAGE_SIZE - 1;   /* Sane caches */
51
52 EXPORT_SYMBOL(shm_align_mask);
53
54 #ifdef CONFIG_MMU
55 /*
56  * To avoid cache aliases, we map the shared page with same color.
57  */
58 #define COLOUR_ALIGN(addr, pgoff)                               \
59         ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
60          (((pgoff) << PAGE_SHIFT) & shm_align_mask))
61
62 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
63         unsigned long len, unsigned long pgoff, unsigned long flags)
64 {
65         struct mm_struct *mm = current->mm;
66         struct vm_area_struct *vma;
67         unsigned long start_addr;
68         int do_colour_align;
69
70         if (flags & MAP_FIXED) {
71                 /* We do not accept a shared mapping if it would violate
72                  * cache aliasing constraints.
73                  */
74                 if ((flags & MAP_SHARED) && (addr & shm_align_mask))
75                         return -EINVAL;
76                 return addr;
77         }
78
79         if (unlikely(len > TASK_SIZE))
80                 return -ENOMEM;
81
82         do_colour_align = 0;
83         if (filp || (flags & MAP_SHARED))
84                 do_colour_align = 1;
85
86         if (addr) {
87                 if (do_colour_align)
88                         addr = COLOUR_ALIGN(addr, pgoff);
89                 else
90                         addr = PAGE_ALIGN(addr);
91
92                 vma = find_vma(mm, addr);
93                 if (TASK_SIZE - len >= addr &&
94                     (!vma || addr + len <= vma->vm_start))
95                         return addr;
96         }
97
98         if (len > mm->cached_hole_size) {
99                 start_addr = addr = mm->free_area_cache;
100         } else {
101                 mm->cached_hole_size = 0;
102                 start_addr = addr = TASK_UNMAPPED_BASE;
103         }
104
105 full_search:
106         if (do_colour_align)
107                 addr = COLOUR_ALIGN(addr, pgoff);
108         else
109                 addr = PAGE_ALIGN(mm->free_area_cache);
110
111         for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
112                 /* At this point:  (!vma || addr < vma->vm_end). */
113                 if (unlikely(TASK_SIZE - len < addr)) {
114                         /*
115                          * Start a new search - just in case we missed
116                          * some holes.
117                          */
118                         if (start_addr != TASK_UNMAPPED_BASE) {
119                                 start_addr = addr = TASK_UNMAPPED_BASE;
120                                 mm->cached_hole_size = 0;
121                                 goto full_search;
122                         }
123                         return -ENOMEM;
124                 }
125                 if (likely(!vma || addr + len <= vma->vm_start)) {
126                         /*
127                          * Remember the place where we stopped the search:
128                          */
129                         mm->free_area_cache = addr + len;
130                         return addr;
131                 }
132                 if (addr + mm->cached_hole_size < vma->vm_start)
133                         mm->cached_hole_size = vma->vm_start - addr;
134
135                 addr = vma->vm_end;
136                 if (do_colour_align)
137                         addr = COLOUR_ALIGN(addr, pgoff);
138         }
139 }
140 #endif /* CONFIG_MMU */
141
142 static inline long
143 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
144          unsigned long flags, int fd, unsigned long pgoff)
145 {
146         int error = -EBADF;
147         struct file *file = NULL;
148
149         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
150         if (!(flags & MAP_ANONYMOUS)) {
151                 file = fget(fd);
152                 if (!file)
153                         goto out;
154         }
155
156         down_write(&current->mm->mmap_sem);
157         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
158         up_write(&current->mm->mmap_sem);
159
160         if (file)
161                 fput(file);
162 out:
163         return error;
164 }
165
166 asmlinkage int old_mmap(unsigned long addr, unsigned long len,
167         unsigned long prot, unsigned long flags,
168         int fd, unsigned long off)
169 {
170         if (off & ~PAGE_MASK)
171                 return -EINVAL;
172         return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
173 }
174
175 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
176         unsigned long prot, unsigned long flags,
177         unsigned long fd, unsigned long pgoff)
178 {
179         return do_mmap2(addr, len, prot, flags, fd, pgoff);
180 }
181
182 /*
183  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
184  *
185  * This is really horribly ugly.
186  */
187 asmlinkage int sys_ipc(uint call, int first, int second,
188                        int third, void __user *ptr, long fifth)
189 {
190         int version, ret;
191
192         version = call >> 16; /* hack for backward compatibility */
193         call &= 0xffff;
194
195         if (call <= SEMCTL)
196                 switch (call) {
197                 case SEMOP:
198                         return sys_semtimedop(first, (struct sembuf __user *)ptr,
199                                               second, NULL);
200                 case SEMTIMEDOP:
201                         return sys_semtimedop(first, (struct sembuf __user *)ptr,
202                                               second,
203                                               (const struct timespec __user *)fifth);
204                 case SEMGET:
205                         return sys_semget (first, second, third);
206                 case SEMCTL: {
207                         union semun fourth;
208                         if (!ptr)
209                                 return -EINVAL;
210                         if (get_user(fourth.__pad, (void * __user *) ptr))
211                                 return -EFAULT;
212                         return sys_semctl (first, second, third, fourth);
213                         }
214                 default:
215                         return -EINVAL;
216                 }
217
218         if (call <= MSGCTL) 
219                 switch (call) {
220                 case MSGSND:
221                         return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
222                                           second, third);
223                 case MSGRCV:
224                         switch (version) {
225                         case 0: {
226                                 struct ipc_kludge tmp;
227                                 if (!ptr)
228                                         return -EINVAL;
229                                 
230                                 if (copy_from_user(&tmp,
231                                                    (struct ipc_kludge __user *) ptr, 
232                                                    sizeof (tmp)))
233                                         return -EFAULT;
234                                 return sys_msgrcv (first, tmp.msgp, second,
235                                                    tmp.msgtyp, third);
236                                 }
237                         default:
238                                 return sys_msgrcv (first,
239                                                    (struct msgbuf __user *) ptr,
240                                                    second, fifth, third);
241                         }
242                 case MSGGET:
243                         return sys_msgget ((key_t) first, second);
244                 case MSGCTL:
245                         return sys_msgctl (first, second,
246                                            (struct msqid_ds __user *) ptr);
247                 default:
248                         return -EINVAL;
249                 }
250         if (call <= SHMCTL) 
251                 switch (call) {
252                 case SHMAT:
253                         switch (version) {
254                         default: {
255                                 ulong raddr;
256                                 ret = do_shmat (first, (char __user *) ptr,
257                                                  second, &raddr);
258                                 if (ret)
259                                         return ret;
260                                 return put_user (raddr, (ulong __user *) third);
261                         }
262                         case 1: /* iBCS2 emulator entry point */
263                                 if (!segment_eq(get_fs(), get_ds()))
264                                         return -EINVAL;
265                                 return do_shmat (first, (char __user *) ptr,
266                                                   second, (ulong *) third);
267                         }
268                 case SHMDT: 
269                         return sys_shmdt ((char __user *)ptr);
270                 case SHMGET:
271                         return sys_shmget (first, second, third);
272                 case SHMCTL:
273                         return sys_shmctl (first, second,
274                                            (struct shmid_ds __user *) ptr);
275                 default:
276                         return -EINVAL;
277                 }
278         
279         return -EINVAL;
280 }
281
282 asmlinkage int sys_uname(struct old_utsname * name)
283 {
284         int err;
285         if (!name)
286                 return -EFAULT;
287         down_read(&uts_sem);
288         err = copy_to_user(name, utsname(), sizeof (*name));
289         up_read(&uts_sem);
290         return err?-EFAULT:0;
291 }
292
293 asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
294                              size_t count, long dummy, loff_t pos)
295 {
296         return sys_pread64(fd, buf, count, pos);
297 }
298
299 asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
300                               size_t count, long dummy, loff_t pos)
301 {
302         return sys_pwrite64(fd, buf, count, pos);
303 }
304
305 asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
306                                 u32 len0, u32 len1, int advice)
307 {
308 #ifdef  __LITTLE_ENDIAN__
309         return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
310                                 (u64)len1 << 32 | len0, advice);
311 #else
312         return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
313                                 (u64)len0 << 32 | len1, advice);
314 #endif
315 }
316
317 #if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
318 #define SYSCALL_ARG3    "trapa #0x23"
319 #else
320 #define SYSCALL_ARG3    "trapa #0x13"
321 #endif
322
323 /*
324  * Do a system call from kernel instead of calling sys_execve so we
325  * end up with proper pt_regs.
326  */
327 int kernel_execve(const char *filename, char *const argv[], char *const envp[])
328 {
329         register long __sc0 __asm__ ("r3") = __NR_execve;
330         register long __sc4 __asm__ ("r4") = (long) filename;
331         register long __sc5 __asm__ ("r5") = (long) argv;
332         register long __sc6 __asm__ ("r6") = (long) envp;
333         __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)       
334                         : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
335                         : "memory");
336         return __sc0;
337 }