Import 2.1.127pre3
[davej-history.git] / arch / sparc64 / kernel / sys_sparc.c
blob08ce072444a04e609b5a84cef92ce2a3a134829f
1 /* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem 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/errno.h>
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/fs.h>
13 #include <linux/file.h>
14 #include <linux/mm.h>
15 #include <linux/sem.h>
16 #include <linux/msg.h>
17 #include <linux/shm.h>
18 #include <linux/stat.h>
19 #include <linux/mman.h>
20 #include <linux/utsname.h>
21 #include <linux/smp.h>
22 #include <linux/smp_lock.h>
23 #include <linux/malloc.h>
25 #include <asm/uaccess.h>
26 #include <asm/ipc.h>
27 #include <asm/utrap.h>
28 #include <asm/perfctr.h>
30 /* XXX Make this per-binary type, this way we can detect the type of
31 * XXX a binary. Every Sparc executable calls this very early on.
33 asmlinkage unsigned longsys_getpagesize(void)
35 return PAGE_SIZE;
38 extern asmlinkage unsigned longsys_brk(unsigned long brk);
40 asmlinkage unsigned longsparc_brk(unsigned long brk)
42 if(brk >=0x80000000000UL)/* VM hole */
43 return current->mm->brk;
44 returnsys_brk(brk);
48 * sys_pipe() is the normal C calling standard for creating
49 * a pipe. It's not the way unix traditionally does this, though.
51 asmlinkage intsparc_pipe(struct pt_regs *regs)
53 int fd[2];
54 int error;
56 lock_kernel();
57 error =do_pipe(fd);
58 if(error)
59 goto out;
60 regs->u_regs[UREG_I1] = fd[1];
61 error = fd[0];
62 out:
63 unlock_kernel();
64 return error;
68 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
70 * This is really horribly ugly.
73 asmlinkage intsys_ipc(unsigned call,int first,int second,unsigned long third,void*ptr,long fifth)
75 int err;
77 lock_kernel();
78 /* No need for backward compatibility. We can start fresh... */
80 if(call <= SEMCTL)
81 switch(call) {
82 case SEMOP:
83 err =sys_semop(first, (struct sembuf *)ptr, second);
84 goto out;
85 case SEMGET:
86 err =sys_semget(first, second, (int)third);
87 goto out;
88 case SEMCTL: {
89 union semun fourth;
90 err = -EINVAL;
91 if(!ptr)
92 goto out;
93 err = -EFAULT;
94 if(get_user(fourth.__pad, (void**)ptr))
95 goto out;
96 err =sys_semctl(first, second, (int)third, fourth);
97 goto out;
99 default:
100 err = -EINVAL;
101 goto out;
103 if(call <= MSGCTL)
104 switch(call) {
105 case MSGSND:
106 err =sys_msgsnd(first, (struct msgbuf *) ptr,
107 second, (int)third);
108 goto out;
109 case MSGRCV:
110 err =sys_msgrcv(first, (struct msgbuf *) ptr, second, fifth, (int)third);
111 goto out;
112 case MSGGET:
113 err =sys_msgget((key_t) first, second);
114 goto out;
115 case MSGCTL:
116 err =sys_msgctl(first, second, (struct msqid_ds *) ptr);
117 goto out;
118 default:
119 err = -EINVAL;
120 goto out;
122 if(call <= SHMCTL)
123 switch(call) {
124 case SHMAT:
125 err =sys_shmat(first, (char*) ptr, second, (ulong *) third);
126 goto out;
127 case SHMDT:
128 err =sys_shmdt((char*)ptr);
129 goto out;
130 case SHMGET:
131 err =sys_shmget(first, second, (int)third);
132 goto out;
133 case SHMCTL:
134 err =sys_shmctl(first, second, (struct shmid_ds *) ptr);
135 goto out;
136 default:
137 err = -EINVAL;
138 goto out;
140 else
141 err = -EINVAL;
142 out:
143 unlock_kernel();
144 return err;
147 /* Linux version of mmap */
148 asmlinkage unsigned longsys_mmap(unsigned long addr,unsigned long len,
149 unsigned long prot,unsigned long flags,unsigned long fd,
150 unsigned long off)
152 struct file * file = NULL;
153 unsigned long retval = -EBADF;
155 down(&current->mm->mmap_sem);
156 lock_kernel();
157 if(!(flags & MAP_ANONYMOUS)) {
158 file =fget(fd);
159 if(!file)
160 goto out;
162 retval = -ENOMEM;
163 len =PAGE_ALIGN(len);
164 if(!(flags & MAP_FIXED) && !addr) {
165 addr =get_unmapped_area(addr, len);
166 if(!addr)
167 goto out_putf;
170 retval = -EINVAL;
171 if(current->tss.flags & SPARC_FLAG_32BIT) {
172 if(len >0xf0000000UL || addr >0xf0000000UL - len)
173 goto out_putf;
174 }else{
175 if(len >=0x80000000000UL ||
176 (addr <0x80000000000UL &&
177 addr >0x80000000000UL-len))
178 goto out_putf;
179 if(addr >=0x80000000000ULL && addr <0xfffff80000000000UL) {
180 /* VM hole */
181 retval = current->mm->brk;
182 goto out_putf;
186 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
187 retval =do_mmap(file, addr, len, prot, flags, off);
189 out_putf:
190 if(file)
191 fput(file);
192 out:
193 unlock_kernel();
194 up(&current->mm->mmap_sem);
195 return retval;
198 /* we come to here via sys_nis_syscall so it can setup the regs argument */
199 asmlinkage unsigned long
200 c_sys_nis_syscall(struct pt_regs *regs)
202 static int count=0;
203 lock_kernel();
204 if(++count <=20) {/* Don't make the system unusable, if someone goes stuck */
205 printk("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
206 show_regs(regs);
208 unlock_kernel();
209 return-ENOSYS;
212 /* #define DEBUG_SPARC_BREAKPOINT */
214 asmlinkage void
215 sparc_breakpoint(struct pt_regs *regs)
217 lock_kernel();
218 #ifdef DEBUG_SPARC_BREAKPOINT
219 printk("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
220 #endif
221 force_sig(SIGTRAP, current);
222 #ifdef DEBUG_SPARC_BREAKPOINT
223 printk("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
224 #endif
225 unlock_kernel();
228 externvoidcheck_pending(int signum);
230 asmlinkage intsys_getdomainname(char*name,int len)
232 int nlen;
233 int err = -EFAULT;
235 down(&uts_sem);
237 nlen =strlen(system_utsname.domainname) +1;
239 if(nlen < len)
240 len = nlen;
241 if(len > __NEW_UTS_LEN)
242 goto done;
243 if(copy_to_user(name, system_utsname.domainname, len))
244 goto done;
245 err =0;
246 done:
247 up(&uts_sem);
248 return err;
251 /* only AP+ systems have sys_aplib */
252 asmlinkage intsys_aplib(void)
254 return-ENOSYS;
257 asmlinkage intsolaris_syscall(struct pt_regs *regs)
259 static int count =0;
260 lock_kernel();
261 regs->tpc = regs->tnpc;
262 regs->tnpc +=4;
263 if(++count <=20)
264 printk("For Solaris binary emulation you need solaris module loaded\n");
265 show_regs(regs);
266 send_sig(SIGSEGV, current,1);
267 unlock_kernel();
268 return-ENOSYS;
271 asmlinkage intsys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
272 utrap_handler_t new_d,
273 utrap_handler_t *old_p, utrap_handler_t *old_d)
275 if(type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
276 return-EINVAL;
277 if(new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
278 if(old_p) {
279 if(!current->tss.utraps)
280 put_user_ret(NULL, old_p, -EFAULT);
281 else
282 put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
284 if(old_d)
285 put_user_ret(NULL, old_d, -EFAULT);
286 return0;
288 lock_kernel();
289 if(!current->tss.utraps) {
290 current->tss.utraps =kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
291 if(!current->tss.utraps)return-ENOMEM;
292 current->tss.utraps[0] =1;
293 memset(current->tss.utraps+1,0, UT_TRAP_INSTRUCTION_31*sizeof(long));
294 }else{
295 if((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] >1) {
296 long*p = current->tss.utraps;
298 current->tss.utraps =kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
299 if(!current->tss.utraps) {
300 current->tss.utraps = p;
301 return-ENOMEM;
303 p[0]--;
304 current->tss.utraps[0] =1;
305 memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
308 if(old_p)
309 put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
310 if(old_d)
311 put_user_ret(NULL, old_d, -EFAULT);
312 current->tss.utraps[type] = (long)new_p;
313 unlock_kernel();
314 return0;
317 longsparc_memory_ordering(unsigned long model,struct pt_regs *regs)
319 if(model >=3)
320 return-EINVAL;
321 regs->tstate = (regs->tstate & ~TSTATE_MM) | (model <<14);
322 return0;
325 asmlinkage int
326 sys_sigaction(int sig,const struct old_sigaction *act,
327 struct old_sigaction *oact)
329 struct k_sigaction new_ka, old_ka;
330 int ret;
332 if(act) {
333 old_sigset_t mask;
334 if(verify_area(VERIFY_READ, act,sizeof(*act)) ||
335 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
336 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
337 return-EFAULT;
338 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
339 __get_user(mask, &act->sa_mask);
340 siginitset(&new_ka.sa.sa_mask, mask);
341 new_ka.ka_restorer = NULL;
344 ret =do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
346 if(!ret && oact) {
347 if(verify_area(VERIFY_WRITE, oact,sizeof(*oact)) ||
348 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
349 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
350 return-EFAULT;
351 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
352 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
355 return ret;
358 asmlinkage int
359 sys_rt_sigaction(int sig,const struct sigaction *act,struct sigaction *oact,
360 void*restorer,size_t sigsetsize)
362 struct k_sigaction new_ka, old_ka;
363 int ret;
365 /* XXX: Don't preclude handling different sized sigset_t's. */
366 if(sigsetsize !=sizeof(sigset_t))
367 return-EINVAL;
369 if(act) {
370 new_ka.ka_restorer = restorer;
371 if(copy_from_user(&new_ka.sa, act,sizeof(*act)))
372 return-EFAULT;
375 ret =do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
377 if(!ret && oact) {
378 if(copy_to_user(oact, &old_ka.sa,sizeof(*oact)))
379 return-EFAULT;
382 return ret;
385 /* Invoked by rtrap code to update performance counters in
386 * user space.
388 asmlinkage void
389 update_perfctrs(void)
391 unsigned long pic, tmp;
393 read_pic(pic);
394 tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
395 __put_user(tmp, current->tss.user_cntd0);
396 tmp = (current->tss.kernel_cntd1 += (pic >>32));
397 __put_user(tmp, current->tss.user_cntd1);
398 reset_pic();
401 asmlinkage int
402 sys_perfctr(int opcode,unsigned long arg0,unsigned long arg1,unsigned long arg2)
404 int err =0;
406 switch(opcode) {
407 case PERFCTR_ON:
408 current->tss.pcr_reg = arg2;
409 current->tss.user_cntd0 = (u64 *) arg0;
410 current->tss.user_cntd1 = (u64 *) arg1;
411 current->tss.kernel_cntd0 =
412 current->tss.kernel_cntd1 =0;
413 write_pcr(arg2);
414 reset_pic();
415 current->tss.flags |= SPARC_FLAG_PERFCTR;
416 break;
418 case PERFCTR_OFF:
419 err = -EINVAL;
420 if((current->tss.flags & SPARC_FLAG_PERFCTR) !=0) {
421 current->tss.user_cntd0 =
422 current->tss.user_cntd1 = NULL;
423 current->tss.pcr_reg =0;
424 write_pcr(0);
425 current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
426 err =0;
428 break;
430 case PERFCTR_READ: {
431 unsigned long pic, tmp;
433 if(!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
434 err = -EINVAL;
435 break;
437 read_pic(pic);
438 tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
439 err |=__put_user(tmp, current->tss.user_cntd0);
440 tmp = (current->tss.kernel_cntd1 += (pic >>32));
441 err |=__put_user(tmp, current->tss.user_cntd1);
442 reset_pic();
443 break;
446 case PERFCTR_CLRPIC:
447 if(!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
448 err = -EINVAL;
449 break;
451 current->tss.kernel_cntd0 =
452 current->tss.kernel_cntd1 =0;
453 reset_pic();
454 break;
456 case PERFCTR_SETPCR: {
457 u64 *user_pcr = (u64 *)arg0;
458 if(!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
459 err = -EINVAL;
460 break;
462 err |=__get_user(current->tss.pcr_reg, user_pcr);
463 write_pcr(current->tss.pcr_reg);
464 current->tss.kernel_cntd0 =
465 current->tss.kernel_cntd1 =0;
466 reset_pic();
467 break;
470 case PERFCTR_GETPCR: {
471 u64 *user_pcr = (u64 *)arg0;
472 if(!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
473 err = -EINVAL;
474 break;
476 err |=__put_user(current->tss.pcr_reg, user_pcr);
477 break;
480 default:
481 err = -EINVAL;
482 break;
484 return err;
close