Import 2.3.36
[davej-history.git] / arch / sparc64 / kernel / sys_sparc.c
blob53d2d8c2d02b525242546e7722e45b7251f8fdba
1 /* $Id: sys_sparc.c,v 1.31 1999/12/21 14:09:25 jj Exp $
2 * linux/arch/sparc64/kernel/sys_sparc.c
4 * This file contains various random system calls that
5 * have a non-standard calling sequence on the Linux/sparc
6 * platform.
7 */
9 #include <linux/config.h>
10 #include <linux/errno.h>
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/fs.h>
14 #include <linux/file.h>
15 #include <linux/mm.h>
16 #include <linux/sem.h>
17 #include <linux/msg.h>
18 #include <linux/shm.h>
19 #include <linux/stat.h>
20 #include <linux/mman.h>
21 #include <linux/utsname.h>
22 #include <linux/smp.h>
23 #include <linux/smp_lock.h>
24 #include <linux/malloc.h>
26 #include <asm/uaccess.h>
27 #include <asm/ipc.h>
28 #include <asm/utrap.h>
29 #include <asm/perfctr.h>
31 /* #define DEBUG_UNIMP_SYSCALL */
33 /* XXX Make this per-binary type, this way we can detect the type of
34 * XXX a binary. Every Sparc executable calls this very early on.
36 asmlinkage unsigned long sys_getpagesize(void)
38 return PAGE_SIZE;
41 extern asmlinkage unsigned long sys_brk(unsigned long brk);
43 asmlinkage unsigned long sparc_brk(unsigned long brk)
45 if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) ||
46 (brk - current->mm->brk > 0x80000000000UL &&
47 brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */
48 return current->mm->brk;
49 return sys_brk(brk);
53 * sys_pipe() is the normal C calling standard for creating
54 * a pipe. It's not the way unix traditionally does this, though.
56 asmlinkage int sparc_pipe(struct pt_regs *regs)
58 int fd[2];
59 int error;
61 lock_kernel();
62 error = do_pipe(fd);
63 if (error)
64 goto out;
65 regs->u_regs[UREG_I1] = fd[1];
66 error = fd[0];
67 out:
68 unlock_kernel();
69 return error;
73 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
75 * This is really horribly ugly.
78 asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long third, void *ptr, long fifth)
80 int err;
82 lock_kernel();
83 /* No need for backward compatibility. We can start fresh... */
85 if (call <= SEMCTL)
86 switch (call) {
87 case SEMOP:
88 err = sys_semop (first, (struct sembuf *)ptr, second);
89 goto out;
90 case SEMGET:
91 err = sys_semget (first, second, (int)third);
92 goto out;
93 case SEMCTL: {
94 union semun fourth;
95 err = -EINVAL;
96 if (!ptr)
97 goto out;
98 err = -EFAULT;
99 if(get_user(fourth.__pad, (void **)ptr))
100 goto out;
101 err = sys_semctl (first, second, (int)third, fourth);
102 goto out;
104 default:
105 err = -EINVAL;
106 goto out;
108 if (call <= MSGCTL)
109 switch (call) {
110 case MSGSND:
111 err = sys_msgsnd (first, (struct msgbuf *) ptr,
112 second, (int)third);
113 goto out;
114 case MSGRCV:
115 err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, (int)third);
116 goto out;
117 case MSGGET:
118 err = sys_msgget ((key_t) first, second);
119 goto out;
120 case MSGCTL:
121 err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
122 goto out;
123 default:
124 err = -EINVAL;
125 goto out;
127 if (call <= SHMCTL)
128 switch (call) {
129 case SHMAT:
130 err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
131 goto out;
132 case SHMDT:
133 err = sys_shmdt ((char *)ptr);
134 goto out;
135 case SHMGET:
136 err = sys_shmget (first, second, (int)third);
137 goto out;
138 case SHMCTL:
139 err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
140 goto out;
141 default:
142 err = -EINVAL;
143 goto out;
145 else
146 err = -EINVAL;
147 out:
148 unlock_kernel();
149 return err;
152 /* Linux version of mmap */
153 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
154 unsigned long prot, unsigned long flags, unsigned long fd,
155 unsigned long off)
157 struct file * file = NULL;
158 unsigned long retval = -EBADF;
160 if (!(flags & MAP_ANONYMOUS)) {
161 file = fget(fd);
162 if (!file)
163 goto out;
165 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
166 retval = -ENOMEM;
167 len = PAGE_ALIGN(len);
168 down(&current->mm->mmap_sem);
169 lock_kernel();
170 if(!(flags & MAP_FIXED) && !addr) {
171 addr = get_unmapped_area(addr, len);
172 if(!addr)
173 goto out_putf;
176 retval = -EINVAL;
177 if (current->thread.flags & SPARC_FLAG_32BIT) {
178 if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
179 goto out_putf;
180 } else {
181 if (len >= 0x80000000000UL ||
182 (addr < 0x80000000000UL &&
183 addr > 0x80000000000UL-len))
184 goto out_putf;
185 if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) {
186 /* VM hole */
187 retval = current->mm->brk;
188 goto out_putf;
192 retval = do_mmap(file, addr, len, prot, flags, off);
194 out_putf:
195 unlock_kernel();
196 up(&current->mm->mmap_sem);
197 if (file)
198 fput(file);
199 out:
200 return retval;
203 /* we come to here via sys_nis_syscall so it can setup the regs argument */
204 asmlinkage unsigned long
205 c_sys_nis_syscall (struct pt_regs *regs)
207 static int count=0;
209 /* Don't make the system unusable, if someone goes stuck */
210 if (count++ > 5) return -ENOSYS;
211 lock_kernel();
212 printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
213 #ifdef DEBUG_UNIMP_SYSCALL
214 show_regs (regs);
215 #endif
216 unlock_kernel();
217 return -ENOSYS;
220 /* #define DEBUG_SPARC_BREAKPOINT */
222 asmlinkage void
223 sparc_breakpoint (struct pt_regs *regs)
225 lock_kernel();
226 #ifdef DEBUG_SPARC_BREAKPOINT
227 printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
228 #endif
229 force_sig(SIGTRAP, current);
230 #ifdef DEBUG_SPARC_BREAKPOINT
231 printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
232 #endif
233 unlock_kernel();
236 extern void check_pending(int signum);
238 asmlinkage int sys_getdomainname(char *name, int len)
240 int nlen;
241 int err = -EFAULT;
243 down(&uts_sem);
245 nlen = strlen(system_utsname.domainname) + 1;
247 if (nlen < len)
248 len = nlen;
249 if(len > __NEW_UTS_LEN)
250 goto done;
251 if(copy_to_user(name, system_utsname.domainname, len))
252 goto done;
253 err = 0;
254 done:
255 up(&uts_sem);
256 return err;
259 /* only AP+ systems have sys_aplib */
260 asmlinkage int sys_aplib(void)
262 return -ENOSYS;
265 asmlinkage int solaris_syscall(struct pt_regs *regs)
267 static int count = 0;
268 lock_kernel();
269 regs->tpc = regs->tnpc;
270 regs->tnpc += 4;
271 if(++count <= 20)
272 printk ("For Solaris binary emulation you need solaris module loaded\n");
273 show_regs (regs);
274 send_sig(SIGSEGV, current, 1);
275 unlock_kernel();
276 return -ENOSYS;
279 #ifndef CONFIG_SUNOS_EMUL
280 asmlinkage int sunos_syscall(struct pt_regs *regs)
282 static int count = 0;
283 lock_kernel();
284 regs->tpc = regs->tnpc;
285 regs->tnpc += 4;
286 if(++count <= 20)
287 printk ("SunOS binary emulation not compiled in\n");
288 force_sig(SIGSEGV, current);
289 unlock_kernel();
290 return -ENOSYS;
292 #endif
294 asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
295 utrap_handler_t new_d,
296 utrap_handler_t *old_p, utrap_handler_t *old_d)
298 if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
299 return -EINVAL;
300 if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
301 if (old_p) {
302 if (!current->thread.utraps)
303 put_user_ret(NULL, old_p, -EFAULT);
304 else
305 put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
307 if (old_d)
308 put_user_ret(NULL, old_d, -EFAULT);
309 return 0;
311 lock_kernel();
312 if (!current->thread.utraps) {
313 current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
314 if (!current->thread.utraps) return -ENOMEM;
315 current->thread.utraps[0] = 1;
316 memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
317 } else {
318 if ((utrap_handler_t)current->thread.utraps[type] != new_p && current->thread.utraps[0] > 1) {
319 long *p = current->thread.utraps;
321 current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
322 if (!current->thread.utraps) {
323 current->thread.utraps = p;
324 return -ENOMEM;
326 p[0]--;
327 current->thread.utraps[0] = 1;
328 memcpy(current->thread.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
331 if (old_p)
332 put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
333 if (old_d)
334 put_user_ret(NULL, old_d, -EFAULT);
335 current->thread.utraps[type] = (long)new_p;
336 unlock_kernel();
337 return 0;
340 long sparc_memory_ordering(unsigned long model, struct pt_regs *regs)
342 if (model >= 3)
343 return -EINVAL;
344 regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
345 return 0;
348 asmlinkage int
349 sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
350 void *restorer, size_t sigsetsize)
352 struct k_sigaction new_ka, old_ka;
353 int ret;
355 /* XXX: Don't preclude handling different sized sigset_t's. */
356 if (sigsetsize != sizeof(sigset_t))
357 return -EINVAL;
359 if (act) {
360 new_ka.ka_restorer = restorer;
361 if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
362 return -EFAULT;
365 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
367 if (!ret && oact) {
368 if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
369 return -EFAULT;
372 return ret;
375 /* Invoked by rtrap code to update performance counters in
376 * user space.
378 asmlinkage void
379 update_perfctrs(void)
381 unsigned long pic, tmp;
383 read_pic(pic);
384 tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
385 __put_user(tmp, current->thread.user_cntd0);
386 tmp = (current->thread.kernel_cntd1 += (pic >> 32));
387 __put_user(tmp, current->thread.user_cntd1);
388 reset_pic();
391 asmlinkage int
392 sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
394 int err = 0;
396 switch(opcode) {
397 case PERFCTR_ON:
398 current->thread.pcr_reg = arg2;
399 current->thread.user_cntd0 = (u64 *) arg0;
400 current->thread.user_cntd1 = (u64 *) arg1;
401 current->thread.kernel_cntd0 =
402 current->thread.kernel_cntd1 = 0;
403 write_pcr(arg2);
404 reset_pic();
405 current->thread.flags |= SPARC_FLAG_PERFCTR;
406 break;
408 case PERFCTR_OFF:
409 err = -EINVAL;
410 if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) {
411 current->thread.user_cntd0 =
412 current->thread.user_cntd1 = NULL;
413 current->thread.pcr_reg = 0;
414 write_pcr(0);
415 current->thread.flags &= ~(SPARC_FLAG_PERFCTR);
416 err = 0;
418 break;
420 case PERFCTR_READ: {
421 unsigned long pic, tmp;
423 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
424 err = -EINVAL;
425 break;
427 read_pic(pic);
428 tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
429 err |= __put_user(tmp, current->thread.user_cntd0);
430 tmp = (current->thread.kernel_cntd1 += (pic >> 32));
431 err |= __put_user(tmp, current->thread.user_cntd1);
432 reset_pic();
433 break;
436 case PERFCTR_CLRPIC:
437 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
438 err = -EINVAL;
439 break;
441 current->thread.kernel_cntd0 =
442 current->thread.kernel_cntd1 = 0;
443 reset_pic();
444 break;
446 case PERFCTR_SETPCR: {
447 u64 *user_pcr = (u64 *)arg0;
448 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
449 err = -EINVAL;
450 break;
452 err |= __get_user(current->thread.pcr_reg, user_pcr);
453 write_pcr(current->thread.pcr_reg);
454 current->thread.kernel_cntd0 =
455 current->thread.kernel_cntd1 = 0;
456 reset_pic();
457 break;
460 case PERFCTR_GETPCR: {
461 u64 *user_pcr = (u64 *)arg0;
462 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
463 err = -EINVAL;
464 break;
466 err |= __put_user(current->thread.pcr_reg, user_pcr);
467 break;
470 default:
471 err = -EINVAL;
472 break;
474 return err;