1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * arch/sh64/kernel/sys_sh64.c
7 *
8 * Copyright (C) 2000, 2001 Paolo Alberelli
9 *
10 * This file contains various random system calls that
11 * have a non-standard calling sequence on the Linux/SH5
12 * platform.
13 *
14 * Mostly taken from i386 version.
15 *
16 */
17
18 #include <linux/errno.h>
19 #include <linux/sched.h>
20 #include <linux/mm.h>
21 #include <linux/smp.h>
22 #include <linux/smp_lock.h>
23 #include <linux/sem.h>
24 #include <linux/msg.h>
25 #include <linux/shm.h>
26 #include <linux/stat.h>
27 #include <linux/mman.h>
28 #include <linux/file.h>
29 #include <linux/utsname.h>
30
31 #include <asm/uaccess.h>
32 #include <asm/ipc.h>
33 #include <asm/ptrace.h>
34
35 #define REG_3 3
36
37 /*
38 * sys_pipe() is the normal C calling standard for creating
39 * a pipe. It's not the way Unix traditionally does this, though.
40 */
41 #ifdef NEW_PIPE_IMPLEMENTATION
sys_pipe(unsigned long * fildes,unsigned long dummy_r3,unsigned long dummy_r4,unsigned long dummy_r5,unsigned long dummy_r6,unsigned long dummy_r7,struct pt_regs * regs)42 asmlinkage int sys_pipe(unsigned long * fildes,
43 unsigned long dummy_r3,
44 unsigned long dummy_r4,
45 unsigned long dummy_r5,
46 unsigned long dummy_r6,
47 unsigned long dummy_r7,
48 struct pt_regs * regs) /* r8 = pt_regs forced by entry.S */
49 {
50 int fd[2];
51 int ret;
52
53 ret = do_pipe(fd);
54 if (ret == 0)
55 /*
56 ***********************************************************************
57 * To avoid the copy_to_user we prefer to break the ABIs convention, *
58 * packing the valid pair of file IDs into a single register (r3); *
59 * while r2 is the return code as defined by the sh5-ABIs. *
60 * BE CAREFUL: pipe stub, into glibc, must be aware of this solution *
61 ***********************************************************************
62
63 #ifdef __LITTLE_ENDIAN__
64 regs->regs[REG_3] = (((unsigned long long) fd[1]) << 32) | ((unsigned long long) fd[0]);
65 #else
66 regs->regs[REG_3] = (((unsigned long long) fd[0]) << 32) | ((unsigned long long) fd[1]);
67 #endif
68
69 */
70 /* although not very clever this is endianess independent */
71 regs->regs[REG_3] = (unsigned long long) *((unsigned long long *) fd);
72
73 return ret;
74 }
75
76 #else
sys_pipe(unsigned long * fildes)77 asmlinkage int sys_pipe(unsigned long * fildes)
78 {
79 int fd[2];
80 int error;
81
82 error = do_pipe(fd);
83 if (!error) {
84 if (copy_to_user(fildes, fd, 2*sizeof(int)))
85 error = -EFAULT;
86 }
87 return error;
88 }
89
90 #endif
91
92 /*
93 * To avoid cache alias, we map the shard page with same color.
94 */
95 #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1))
96
arch_get_unmapped_area(struct file * filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)97 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
98 unsigned long len, unsigned long pgoff, unsigned long flags)
99 {
100 struct vm_area_struct *vma;
101
102 if (flags & MAP_FIXED) {
103 /* We do not accept a shared mapping if it would violate
104 * cache aliasing constraints.
105 */
106 if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
107 return -EINVAL;
108 return addr;
109 }
110
111 if (len > TASK_SIZE)
112 return -ENOMEM;
113 if (!addr)
114 addr = TASK_UNMAPPED_BASE;
115
116 if (flags & MAP_PRIVATE)
117 addr = PAGE_ALIGN(addr);
118 else
119 addr = COLOUR_ALIGN(addr);
120
121 for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
122 /* At this point: (!vma || addr < vma->vm_end). */
123 if (TASK_SIZE - len < addr)
124 return -ENOMEM;
125 if (!vma || addr + len <= vma->vm_start)
126 return addr;
127 addr = vma->vm_end;
128 if (!(flags & MAP_PRIVATE))
129 addr = COLOUR_ALIGN(addr);
130 }
131 }
132
sys_shmatcall(int shmid,void * shmaddr,int shmflg)133 asmlinkage long sys_shmatcall(int shmid, void *shmaddr, int shmflg)
134 {
135 unsigned long raddr;
136 long err;
137
138 lock_kernel();
139 err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
140 if (err)
141 goto out_shmatcall;
142
143 err = raddr;
144 out_shmatcall:
145 unlock_kernel();
146 return err;
147 }
148
149 /* common code for old and new mmaps */
do_mmap2(unsigned long addr,unsigned long len,unsigned long prot,unsigned long flags,unsigned long fd,unsigned long pgoff)150 static inline long do_mmap2(
151 unsigned long addr, unsigned long len,
152 unsigned long prot, unsigned long flags,
153 unsigned long fd, unsigned long pgoff)
154 {
155 int error = -EBADF;
156 struct file * file = NULL;
157
158 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
159 if (!(flags & MAP_ANONYMOUS)) {
160 file = fget(fd);
161 if (!file)
162 goto out;
163 }
164
165 down_write(¤t->mm->mmap_sem);
166 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
167 up_write(¤t->mm->mmap_sem);
168
169 if (file)
170 fput(file);
171 out:
172 return error;
173 }
174
sys_mmap2(unsigned long addr,unsigned long len,unsigned long prot,unsigned long flags,unsigned long fd,unsigned long pgoff)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
old_mmap(unsigned long addr,unsigned long len,unsigned long prot,unsigned long flags,int fd,unsigned long off)182 asmlinkage int old_mmap(unsigned long addr, unsigned long len,
183 unsigned long prot, unsigned long flags,
184 int fd, unsigned long off)
185 {
186 if (off & ~PAGE_MASK)
187 return -EINVAL;
188 return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
189 }
190
191 /*******************************************************************
192 * sys_ipc() is the de-multiplexer for the SysV IPC calls... *
193 * *
194 * This is really horribly ugly. *
195 * --- *
196 * True! But this is a obsolete ipc system calls implementation; *
197 * infact, all ipc system calls are called, such as alpha and *
198 * ia64 systems, without the "de-multiplexer" routine (except the *
199 * shmat syscall that is called by the sys_shmatcall function). *
200 * --- *
201 * *
202 *******************************************************************/
sys_ipc(uint call,int first,int second,int third,void * ptr,long fifth)203 asmlinkage int sys_ipc(uint call, int first, int second,
204 int third, void *ptr, long fifth)
205 {
206 int version, ret;
207
208 version = call >> 16; /* hack for backward compatibility */
209 call &= 0xffff;
210
211 if (call <= SEMCTL)
212 switch (call) {
213 case SEMOP:
214 return sys_semop (first, (struct sembuf *)ptr, second);
215 case SEMGET:
216 return sys_semget (first, second, third);
217 case SEMCTL: {
218 union semun fourth;
219 if (!ptr)
220 return -EINVAL;
221 if (get_user(fourth.__pad, (void **) ptr))
222 return -EFAULT;
223 return sys_semctl (first, second, third, fourth);
224 }
225 default:
226 return -EINVAL;
227 }
228
229 if (call <= MSGCTL)
230 switch (call) {
231 case MSGSND:
232 return sys_msgsnd (first, (struct msgbuf *) ptr,
233 second, third);
234 case MSGRCV:
235 switch (version) {
236 case 0: {
237 struct ipc_kludge tmp;
238 if (!ptr)
239 return -EINVAL;
240
241 if (copy_from_user(&tmp,
242 (struct ipc_kludge *) ptr,
243 sizeof (tmp)))
244 return -EFAULT;
245 return sys_msgrcv (first, tmp.msgp, second,
246 tmp.msgtyp, third);
247 }
248 default:
249 return sys_msgrcv (first,
250 (struct msgbuf *) ptr,
251 second, fifth, third);
252 }
253 case MSGGET:
254 return sys_msgget ((key_t) first, second);
255 case MSGCTL:
256 return sys_msgctl (first, second,
257 (struct msqid_ds *) ptr);
258 default:
259 return -EINVAL;
260 }
261 if (call <= SHMCTL)
262 switch (call) {
263 case SHMAT:
264 switch (version) {
265 default: {
266 ulong raddr;
267 ret = sys_shmat (first, (char *) ptr,
268 second, &raddr);
269 if (ret)
270 return ret;
271 return put_user (raddr, (ulong *) third);
272 }
273 case 1: /* iBCS2 emulator entry point */
274 if (!segment_eq(get_fs(), get_ds()))
275 return -EINVAL;
276 return sys_shmat (first, (char *) ptr,
277 second, (ulong *) third);
278 }
279 case SHMDT:
280 return sys_shmdt ((char *)ptr);
281 case SHMGET:
282 return sys_shmget (first, second, third);
283 case SHMCTL:
284 return sys_shmctl (first, second,
285 (struct shmid_ds *) ptr);
286 default:
287 return -EINVAL;
288 }
289
290 return -EINVAL;
291 }
292
sys_uname(struct old_utsname * name)293 asmlinkage int sys_uname(struct old_utsname * name)
294 {
295 int err;
296 if (!name)
297 return -EFAULT;
298 down_read(&uts_sem);
299 err=copy_to_user(name, &system_utsname, sizeof (*name));
300 up_read(&uts_sem);
301 return err?-EFAULT:0;
302 }
303
sys_pause(void)304 asmlinkage int sys_pause(void)
305 {
306 current->state = TASK_INTERRUPTIBLE;
307 schedule();
308 return -ERESTARTNOHAND;
309 }
310