Import 2.3.18pre1
[davej-history.git] / arch / sparc64 / kernel / sys_sparc.c
blob4e87819d44c83af98811cd55ba97c58944b75483
1 /* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 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/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 /* #define DEBUG_UNIMP_SYSCALL */
32 /* XXX Make this per-binary type, this way we can detect the type of
33 * XXX a binary. Every Sparc executable calls this very early on.
35 asmlinkage unsigned long sys_getpagesize(void)
37 return PAGE_SIZE;
40 extern asmlinkage unsigned long sys_brk(unsigned long brk);
42 asmlinkage unsigned long sparc_brk(unsigned long brk)
44 if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) ||
45 (brk - current->mm->brk > 0x80000000000UL &&
46 brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */
47 return current->mm->brk;
48 return sys_brk(brk);
52 * sys_pipe() is the normal C calling standard for creating
53 * a pipe. It's not the way unix traditionally does this, though.
55 asmlinkage int sparc_pipe(struct pt_regs *regs)
57 int fd[2];
58 int error;
60 lock_kernel();
61 error = do_pipe(fd);
62 if (error)
63 goto out;
64 regs->u_regs[UREG_I1] = fd[1];
65 error = fd[0];
66 out:
67 unlock_kernel();
68 return error;
72 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
74 * This is really horribly ugly.
77 asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long third, void *ptr, long fifth)
79 int err;
81 lock_kernel();
82 /* No need for backward compatibility. We can start fresh... */
84 if (call <= SEMCTL)
85 switch (call) {
86 case SEMOP:
87 err = sys_semop (first, (struct sembuf *)ptr, second);
88 goto out;
89 case SEMGET:
90 err = sys_semget (first, second, (int)third);
91 goto out;
92 case SEMCTL: {
93 union semun fourth;
94 err = -EINVAL;
95 if (!ptr)
96 goto out;
97 err = -EFAULT;
98 if(get_user(fourth.__pad, (void **)ptr))
99 goto out;
100 err = sys_semctl (first, second, (int)third, fourth);
101 goto out;
103 default:
104 err = -EINVAL;
105 goto out;
107 if (call <= MSGCTL)
108 switch (call) {
109 case MSGSND:
110 err = sys_msgsnd (first, (struct msgbuf *) ptr,
111 second, (int)third);
112 goto out;
113 case MSGRCV:
114 err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, (int)third);
115 goto out;
116 case MSGGET:
117 err = sys_msgget ((key_t) first, second);
118 goto out;
119 case MSGCTL:
120 err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
121 goto out;
122 default:
123 err = -EINVAL;
124 goto out;
126 if (call <= SHMCTL)
127 switch (call) {
128 case SHMAT:
129 err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
130 goto out;
131 case SHMDT:
132 err = sys_shmdt ((char *)ptr);
133 goto out;
134 case SHMGET:
135 err = sys_shmget (first, second, (int)third);
136 goto out;
137 case SHMCTL:
138 err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
139 goto out;
140 default:
141 err = -EINVAL;
142 goto out;
144 else
145 err = -EINVAL;
146 out:
147 unlock_kernel();
148 return err;
151 /* Linux version of mmap */
152 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
153 unsigned long prot, unsigned long flags, unsigned long fd,
154 unsigned long off)
156 struct file * file = NULL;
157 unsigned long retval = -EBADF;
159 down(&current->mm->mmap_sem);
160 lock_kernel();
161 if (!(flags & MAP_ANONYMOUS)) {
162 file = fget(fd);
163 if (!file)
164 goto out;
166 retval = -ENOMEM;
167 len = PAGE_ALIGN(len);
168 if(!(flags & MAP_FIXED) && !addr) {
169 addr = get_unmapped_area(addr, len);
170 if(!addr)
171 goto out_putf;
174 retval = -EINVAL;
175 if (current->thread.flags & SPARC_FLAG_32BIT) {
176 if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
177 goto out_putf;
178 } else {
179 if (len >= 0x80000000000UL ||
180 (addr < 0x80000000000UL &&
181 addr > 0x80000000000UL-len))
182 goto out_putf;
183 if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) {
184 /* VM hole */
185 retval = current->mm->brk;
186 goto out_putf;
190 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
191 retval = do_mmap(file, addr, len, prot, flags, off);
193 out_putf:
194 if (file)
195 fput(file);
196 out:
197 unlock_kernel();
198 up(&current->mm->mmap_sem);
199 return retval;
202 /* we come to here via sys_nis_syscall so it can setup the regs argument */
203 asmlinkage unsigned long
204 c_sys_nis_syscall (struct pt_regs *regs)
206 static int count=0;
208 /* Don't make the system unusable, if someone goes stuck */
209 if (count++ > 5) return -ENOSYS;
210 lock_kernel();
211 printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
212 #ifdef DEBUG_UNIMP_SYSCALL
213 show_regs (regs);
214 #endif
215 unlock_kernel();
216 return -ENOSYS;
219 /* #define DEBUG_SPARC_BREAKPOINT */
221 asmlinkage void
222 sparc_breakpoint (struct pt_regs *regs)
224 lock_kernel();
225 #ifdef DEBUG_SPARC_BREAKPOINT
226 printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
227 #endif
228 force_sig(SIGTRAP, current);
229 #ifdef DEBUG_SPARC_BREAKPOINT
230 printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
231 #endif
232 unlock_kernel();
235 extern void check_pending(int signum);
237 asmlinkage int sys_getdomainname(char *name, int len)
239 int nlen;
240 int err = -EFAULT;
242 down(&uts_sem);
244 nlen = strlen(system_utsname.domainname) + 1;
246 if (nlen < len)
247 len = nlen;
248 if(len > __NEW_UTS_LEN)
249 goto done;
250 if(copy_to_user(name, system_utsname.domainname, len))
251 goto done;
252 err = 0;
253 done:
254 up(&uts_sem);
255 return err;
258 /* only AP+ systems have sys_aplib */
259 asmlinkage int sys_aplib(void)
261 return -ENOSYS;
264 asmlinkage int solaris_syscall(struct pt_regs *regs)
266 static int count = 0;
267 lock_kernel();
268 regs->tpc = regs->tnpc;
269 regs->tnpc += 4;
270 if(++count <= 20)
271 printk ("For Solaris binary emulation you need solaris module loaded\n");
272 show_regs (regs);
273 send_sig(SIGSEGV, current, 1);
274 unlock_kernel();
275 return -ENOSYS;
278 asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
279 utrap_handler_t new_d,
280 utrap_handler_t *old_p, utrap_handler_t *old_d)
282 if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
283 return -EINVAL;
284 if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
285 if (old_p) {
286 if (!current->thread.utraps)
287 put_user_ret(NULL, old_p, -EFAULT);
288 else
289 put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
291 if (old_d)
292 put_user_ret(NULL, old_d, -EFAULT);
293 return 0;
295 lock_kernel();
296 if (!current->thread.utraps) {
297 current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
298 if (!current->thread.utraps) return -ENOMEM;
299 current->thread.utraps[0] = 1;
300 memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
301 } else {
302 if ((utrap_handler_t)current->thread.utraps[type] != new_p && current->thread.utraps[0] > 1) {
303 long *p = current->thread.utraps;
305 current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
306 if (!current->thread.utraps) {
307 current->thread.utraps = p;
308 return -ENOMEM;
310 p[0]--;
311 current->thread.utraps[0] = 1;
312 memcpy(current->thread.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
315 if (old_p)
316 put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
317 if (old_d)
318 put_user_ret(NULL, old_d, -EFAULT);
319 current->thread.utraps[type] = (long)new_p;
320 unlock_kernel();
321 return 0;
324 long sparc_memory_ordering(unsigned long model, struct pt_regs *regs)
326 if (model >= 3)
327 return -EINVAL;
328 regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
329 return 0;
332 asmlinkage int
333 sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
334 void *restorer, size_t sigsetsize)
336 struct k_sigaction new_ka, old_ka;
337 int ret;
339 /* XXX: Don't preclude handling different sized sigset_t's. */
340 if (sigsetsize != sizeof(sigset_t))
341 return -EINVAL;
343 if (act) {
344 new_ka.ka_restorer = restorer;
345 if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
346 return -EFAULT;
349 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
351 if (!ret && oact) {
352 if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
353 return -EFAULT;
356 return ret;
359 /* Invoked by rtrap code to update performance counters in
360 * user space.
362 asmlinkage void
363 update_perfctrs(void)
365 unsigned long pic, tmp;
367 read_pic(pic);
368 tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
369 __put_user(tmp, current->thread.user_cntd0);
370 tmp = (current->thread.kernel_cntd1 += (pic >> 32));
371 __put_user(tmp, current->thread.user_cntd1);
372 reset_pic();
375 asmlinkage int
376 sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
378 int err = 0;
380 switch(opcode) {
381 case PERFCTR_ON:
382 current->thread.pcr_reg = arg2;
383 current->thread.user_cntd0 = (u64 *) arg0;
384 current->thread.user_cntd1 = (u64 *) arg1;
385 current->thread.kernel_cntd0 =
386 current->thread.kernel_cntd1 = 0;
387 write_pcr(arg2);
388 reset_pic();
389 current->thread.flags |= SPARC_FLAG_PERFCTR;
390 break;
392 case PERFCTR_OFF:
393 err = -EINVAL;
394 if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) {
395 current->thread.user_cntd0 =
396 current->thread.user_cntd1 = NULL;
397 current->thread.pcr_reg = 0;
398 write_pcr(0);
399 current->thread.flags &= ~(SPARC_FLAG_PERFCTR);
400 err = 0;
402 break;
404 case PERFCTR_READ: {
405 unsigned long pic, tmp;
407 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
408 err = -EINVAL;
409 break;
411 read_pic(pic);
412 tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
413 err |= __put_user(tmp, current->thread.user_cntd0);
414 tmp = (current->thread.kernel_cntd1 += (pic >> 32));
415 err |= __put_user(tmp, current->thread.user_cntd1);
416 reset_pic();
417 break;
420 case PERFCTR_CLRPIC:
421 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
422 err = -EINVAL;
423 break;
425 current->thread.kernel_cntd0 =
426 current->thread.kernel_cntd1 = 0;
427 reset_pic();
428 break;
430 case PERFCTR_SETPCR: {
431 u64 *user_pcr = (u64 *)arg0;
432 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
433 err = -EINVAL;
434 break;
436 err |= __get_user(current->thread.pcr_reg, user_pcr);
437 write_pcr(current->thread.pcr_reg);
438 current->thread.kernel_cntd0 =
439 current->thread.kernel_cntd1 = 0;
440 reset_pic();
441 break;
444 case PERFCTR_GETPCR: {
445 u64 *user_pcr = (u64 *)arg0;
446 if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
447 err = -EINVAL;
448 break;
450 err |= __put_user(current->thread.pcr_reg, user_pcr);
451 break;
454 default:
455 err = -EINVAL;
456 break;
458 return err;