patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / sparc64 / kernel / sys_sparc.c
1 /* $Id: sys_sparc.c,v 1.57 2002/02/09 19:49:30 davem Exp $
2  * linux/arch/sparc64/kernel/sys_sparc.c
3  *
4  * This file contains various random system calls that
5  * have a non-standard calling sequence on the Linux/sparc
6  * platform.
7  */
8
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/slab.h>
25 #include <linux/syscalls.h>
26 #include <linux/ipc.h>
27 #include <linux/personality.h>
28 #include <linux/vs_cvirt.h>
29
30 #include <asm/uaccess.h>
31 #include <asm/ipc.h>
32 #include <asm/utrap.h>
33 #include <asm/perfctr.h>
34
35 /* #define DEBUG_UNIMP_SYSCALL */
36
37 /* XXX Make this per-binary type, this way we can detect the type of
38  * XXX a binary.  Every Sparc executable calls this very early on.
39  */
40 asmlinkage unsigned long sys_getpagesize(void)
41 {
42         return PAGE_SIZE;
43 }
44
45 #define COLOUR_ALIGN(addr,pgoff)                \
46         ((((addr)+SHMLBA-1)&~(SHMLBA-1)) +      \
47          (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
48
49 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
50 {
51         struct mm_struct *mm = current->mm;
52         struct vm_area_struct * vma;
53         unsigned long task_size = TASK_SIZE;
54         unsigned long start_addr;
55         int do_color_align;
56
57         if (flags & MAP_FIXED) {
58                 /* We do not accept a shared mapping if it would violate
59                  * cache aliasing constraints.
60                  */
61                 if ((flags & MAP_SHARED) &&
62                     ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
63                         return -EINVAL;
64                 return addr;
65         }
66
67         if (test_thread_flag(TIF_32BIT))
68                 task_size = 0xf0000000UL;
69         if (len > task_size || len > -PAGE_OFFSET)
70                 return -ENOMEM;
71
72         do_color_align = 0;
73         if (filp || (flags & MAP_SHARED))
74                 do_color_align = 1;
75
76         if (addr) {
77                 if (do_color_align)
78                         addr = COLOUR_ALIGN(addr, pgoff);
79                 else
80                         addr = PAGE_ALIGN(addr);
81
82                 vma = find_vma(mm, addr);
83                 if (task_size - len >= addr &&
84                     (!vma || addr + len <= vma->vm_start))
85                         return addr;
86         }
87
88         start_addr = addr = mm->free_area_cache;
89
90         task_size -= len;
91
92 full_search:
93         if (do_color_align)
94                 addr = COLOUR_ALIGN(addr, pgoff);
95         else
96                 addr = PAGE_ALIGN(addr);
97
98         for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
99                 /* At this point:  (!vma || addr < vma->vm_end). */
100                 if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) {
101                         addr = PAGE_OFFSET;
102                         vma = find_vma(mm, PAGE_OFFSET);
103                 }
104                 if (task_size < addr) {
105                         if (start_addr != TASK_UNMAPPED_BASE) {
106                                 start_addr = addr = TASK_UNMAPPED_BASE;
107                                 goto full_search;
108                         }
109                         return -ENOMEM;
110                 }
111                 if (!vma || addr + len <= vma->vm_start) {
112                         /*
113                          * Remember the place where we stopped the search:
114                          */
115                         mm->free_area_cache = addr + len;
116                         return addr;
117                 }
118                 addr = vma->vm_end;
119                 if (do_color_align)
120                         addr = COLOUR_ALIGN(addr, pgoff);
121         }
122 }
123
124 /* Try to align mapping such that we align it as much as possible. */
125 unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
126 {
127         unsigned long align_goal, addr = -ENOMEM;
128
129         if (flags & MAP_FIXED) {
130                 /* Ok, don't mess with it. */
131                 return get_unmapped_area(NULL, addr, len, pgoff, flags);
132         }
133         flags &= ~MAP_SHARED;
134
135         align_goal = PAGE_SIZE;
136         if (len >= (4UL * 1024 * 1024))
137                 align_goal = (4UL * 1024 * 1024);
138         else if (len >= (512UL * 1024))
139                 align_goal = (512UL * 1024);
140         else if (len >= (64UL * 1024))
141                 align_goal = (64UL * 1024);
142
143         do {
144                 addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags);
145                 if (!(addr & ~PAGE_MASK)) {
146                         addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL);
147                         break;
148                 }
149
150                 if (align_goal == (4UL * 1024 * 1024))
151                         align_goal = (512UL * 1024);
152                 else if (align_goal == (512UL * 1024))
153                         align_goal = (64UL * 1024);
154                 else
155                         align_goal = PAGE_SIZE;
156         } while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE);
157
158         /* Mapping is smaller than 64K or larger areas could not
159          * be obtained.
160          */
161         if (addr & ~PAGE_MASK)
162                 addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
163
164         return addr;
165 }
166
167 asmlinkage unsigned long sparc_brk(unsigned long brk)
168 {
169         /* People could try to be nasty and use ta 0x6d in 32bit programs */
170         if (test_thread_flag(TIF_32BIT) &&
171             brk >= 0xf0000000UL)
172                 return current->mm->brk;
173
174         if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET))
175                 return current->mm->brk;
176         return sys_brk(brk);
177 }
178                                                                 
179 /*
180  * sys_pipe() is the normal C calling standard for creating
181  * a pipe. It's not the way unix traditionally does this, though.
182  */
183 asmlinkage long sparc_pipe(struct pt_regs *regs)
184 {
185         int fd[2];
186         int error;
187
188         error = do_pipe(fd);
189         if (error)
190                 goto out;
191         regs->u_regs[UREG_I1] = fd[1];
192         error = fd[0];
193 out:
194         return error;
195 }
196
197 /*
198  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
199  *
200  * This is really horribly ugly.
201  */
202
203 asmlinkage long sys_ipc(unsigned int call, int first, int second, unsigned long third, void __user *ptr, long fifth)
204 {
205         int err;
206
207         /* No need for backward compatibility. We can start fresh... */
208         if (call <= SEMCTL) {
209                 switch (call) {
210                 case SEMOP:
211                         err = sys_semtimedop(first, ptr, second, NULL);
212                         goto out;
213                 case SEMTIMEDOP:
214                         err = sys_semtimedop(first, ptr, second,
215                                 (const struct timespec __user *) fifth);
216                         goto out;
217                 case SEMGET:
218                         err = sys_semget(first, second, (int)third);
219                         goto out;
220                 case SEMCTL: {
221                         union semun fourth;
222                         err = -EINVAL;
223                         if (!ptr)
224                                 goto out;
225                         err = -EFAULT;
226                         if (get_user(fourth.__pad,
227                                      (void __user * __user *) ptr))
228                                 goto out;
229                         err = sys_semctl(first, second | IPC_64,
230                                          (int)third, fourth);
231                         goto out;
232                 }
233                 default:
234                         err = -ENOSYS;
235                         goto out;
236                 };
237         }
238         if (call <= MSGCTL) {
239                 switch (call) {
240                 case MSGSND:
241                         err = sys_msgsnd(first, ptr, second, (int)third);
242                         goto out;
243                 case MSGRCV:
244                         err = sys_msgrcv(first, ptr, second, fifth,
245                                          (int)third);
246                         goto out;
247                 case MSGGET:
248                         err = sys_msgget((key_t) first, second);
249                         goto out;
250                 case MSGCTL:
251                         err = sys_msgctl(first, second | IPC_64, ptr);
252                         goto out;
253                 default:
254                         err = -ENOSYS;
255                         goto out;
256                 };
257         }
258         if (call <= SHMCTL) {
259                 switch (call) {
260                 case SHMAT: {
261                         ulong raddr;
262                         err = do_shmat(first, ptr, second, &raddr);
263                         if (!err) {
264                                 if (put_user(raddr,
265                                              (ulong __user *) third))
266                                         err = -EFAULT;
267                         }
268                         goto out;
269                 }
270                 case SHMDT:
271                         err = sys_shmdt(ptr);
272                         goto out;
273                 case SHMGET:
274                         err = sys_shmget(first, second, (int)third);
275                         goto out;
276                 case SHMCTL:
277                         err = sys_shmctl(first, second | IPC_64, ptr);
278                         goto out;
279                 default:
280                         err = -ENOSYS;
281                         goto out;
282                 };
283         } else {
284                 err = -ENOSYS;
285         }
286 out:
287         return err;
288 }
289
290 asmlinkage long sparc64_newuname(struct new_utsname __user *name)
291 {
292         int ret = sys_newuname(name);
293         
294         if (current->personality == PER_LINUX32 && !ret) {
295                 ret = (copy_to_user(name->machine, "sparc\0\0", 8)
296                        ? -EFAULT : 0);
297         }
298         return ret;
299 }
300
301 asmlinkage long sparc64_personality(unsigned long personality)
302 {
303         int ret;
304
305         if (current->personality == PER_LINUX32 &&
306             personality == PER_LINUX)
307                 personality = PER_LINUX32;
308         ret = sys_personality(personality);
309         if (ret == PER_LINUX32)
310                 ret = PER_LINUX;
311
312         return ret;
313 }
314
315 /* Linux version of mmap */
316 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
317         unsigned long prot, unsigned long flags, unsigned long fd,
318         unsigned long off)
319 {
320         struct file * file = NULL;
321         unsigned long retval = -EBADF;
322
323         if (!(flags & MAP_ANONYMOUS)) {
324                 file = fget(fd);
325                 if (!file)
326                         goto out;
327         }
328         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
329         len = PAGE_ALIGN(len);
330         retval = -EINVAL;
331
332         if (test_thread_flag(TIF_32BIT)) {
333                 if (len > 0xf0000000UL ||
334                     ((flags & MAP_FIXED) && addr > 0xf0000000UL - len))
335                         goto out_putf;
336         } else {
337                 if (len > -PAGE_OFFSET ||
338                     ((flags & MAP_FIXED) &&
339                      addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
340                         goto out_putf;
341         }
342
343         down_write(&current->mm->mmap_sem);
344         retval = do_mmap(file, addr, len, prot, flags, off);
345         up_write(&current->mm->mmap_sem);
346
347 out_putf:
348         if (file)
349                 fput(file);
350 out:
351         return retval;
352 }
353
354 asmlinkage long sys64_munmap(unsigned long addr, size_t len)
355 {
356         long ret;
357
358         if (len > -PAGE_OFFSET ||
359             (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
360                 return -EINVAL;
361         down_write(&current->mm->mmap_sem);
362         ret = do_munmap(current->mm, addr, len);
363         up_write(&current->mm->mmap_sem);
364         return ret;
365 }
366
367 extern unsigned long do_mremap(unsigned long addr,
368         unsigned long old_len, unsigned long new_len,
369         unsigned long flags, unsigned long new_addr);
370                 
371 asmlinkage unsigned long sys64_mremap(unsigned long addr,
372         unsigned long old_len, unsigned long new_len,
373         unsigned long flags, unsigned long new_addr)
374 {
375         struct vm_area_struct *vma;
376         unsigned long ret = -EINVAL;
377         if (test_thread_flag(TIF_32BIT))
378                 goto out;
379         if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET)
380                 goto out;
381         if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET)
382                 goto out;
383         down_write(&current->mm->mmap_sem);
384         if (flags & MREMAP_FIXED) {
385                 if (new_addr < PAGE_OFFSET &&
386                     new_addr + new_len > -PAGE_OFFSET)
387                         goto out_sem;
388         } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) {
389                 unsigned long map_flags = 0;
390                 struct file *file = NULL;
391
392                 ret = -ENOMEM;
393                 if (!(flags & MREMAP_MAYMOVE))
394                         goto out_sem;
395
396                 vma = find_vma(current->mm, addr);
397                 if (vma) {
398                         if (vma->vm_flags & VM_SHARED)
399                                 map_flags |= MAP_SHARED;
400                         file = vma->vm_file;
401                 }
402
403                 /* MREMAP_FIXED checked above. */
404                 new_addr = get_unmapped_area(file, addr, new_len,
405                                     vma ? vma->vm_pgoff : 0,
406                                     map_flags);
407                 ret = new_addr;
408                 if (new_addr & ~PAGE_MASK)
409                         goto out_sem;
410                 flags |= MREMAP_FIXED;
411         }
412         ret = do_mremap(addr, old_len, new_len, flags, new_addr);
413 out_sem:
414         up_write(&current->mm->mmap_sem);
415 out:
416         return ret;       
417 }
418
419 /* we come to here via sys_nis_syscall so it can setup the regs argument */
420 asmlinkage unsigned long c_sys_nis_syscall(struct pt_regs *regs)
421 {
422         static int count;
423         
424         /* Don't make the system unusable, if someone goes stuck */
425         if (count++ > 5)
426                 return -ENOSYS;
427
428         printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
429 #ifdef DEBUG_UNIMP_SYSCALL      
430         show_regs (regs);
431 #endif
432
433         return -ENOSYS;
434 }
435
436 /* #define DEBUG_SPARC_BREAKPOINT */
437
438 asmlinkage void sparc_breakpoint(struct pt_regs *regs)
439 {
440         siginfo_t info;
441
442         if (test_thread_flag(TIF_32BIT)) {
443                 regs->tpc &= 0xffffffff;
444                 regs->tnpc &= 0xffffffff;
445         }
446 #ifdef DEBUG_SPARC_BREAKPOINT
447         printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
448 #endif
449         info.si_signo = SIGTRAP;
450         info.si_errno = 0;
451         info.si_code = TRAP_BRKPT;
452         info.si_addr = (void *)regs->tpc;
453         info.si_trapno = 0;
454         force_sig_info(SIGTRAP, &info, current);
455 #ifdef DEBUG_SPARC_BREAKPOINT
456         printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
457 #endif
458 }
459
460 extern void check_pending(int signum);
461
462 asmlinkage long sys_getdomainname(char __user *name, int len)
463 {
464         int nlen;
465         int err = -EFAULT;
466
467         down_read(&uts_sem);
468         
469         nlen = strlen(vx_new_uts(domainname)) + 1;
470
471         if (nlen < len)
472                 len = nlen;
473         if (len > __NEW_UTS_LEN)
474                 goto done;
475         if (copy_to_user(name, vx_new_uts(domainname), len))
476                 goto done;
477         err = 0;
478 done:
479         up_read(&uts_sem);
480         return err;
481 }
482
483 asmlinkage long solaris_syscall(struct pt_regs *regs)
484 {
485         static int count;
486
487         regs->tpc = regs->tnpc;
488         regs->tnpc += 4;
489         if (test_thread_flag(TIF_32BIT)) {
490                 regs->tpc &= 0xffffffff;
491                 regs->tnpc &= 0xffffffff;
492         }
493         if (++count <= 5) {
494                 printk ("For Solaris binary emulation you need solaris module loaded\n");
495                 show_regs (regs);
496         }
497         send_sig(SIGSEGV, current, 1);
498
499         return -ENOSYS;
500 }
501
502 #ifndef CONFIG_SUNOS_EMUL
503 asmlinkage long sunos_syscall(struct pt_regs *regs)
504 {
505         static int count;
506
507         regs->tpc = regs->tnpc;
508         regs->tnpc += 4;
509         if (test_thread_flag(TIF_32BIT)) {
510                 regs->tpc &= 0xffffffff;
511                 regs->tnpc &= 0xffffffff;
512         }
513         if (++count <= 20)
514                 printk ("SunOS binary emulation not compiled in\n");
515         force_sig(SIGSEGV, current);
516
517         return -ENOSYS;
518 }
519 #endif
520
521 asmlinkage long sys_utrap_install(utrap_entry_t type,
522                                   utrap_handler_t new_p,
523                                   utrap_handler_t new_d,
524                                   utrap_handler_t __user *old_p,
525                                   utrap_handler_t __user *old_d)
526 {
527         if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
528                 return -EINVAL;
529         if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
530                 if (old_p) {
531                         if (!current_thread_info()->utraps) {
532                                 if (put_user(NULL, old_p))
533                                         return -EFAULT;
534                         } else {
535                                 if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
536                                         return -EFAULT;
537                         }
538                 }
539                 if (old_d) {
540                         if (put_user(NULL, old_d))
541                                 return -EFAULT;
542                 }
543                 return 0;
544         }
545         if (!current_thread_info()->utraps) {
546                 current_thread_info()->utraps =
547                         kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
548                 if (!current_thread_info()->utraps)
549                         return -ENOMEM;
550                 current_thread_info()->utraps[0] = 1;
551                 memset(current_thread_info()->utraps+1, 0,
552                        UT_TRAP_INSTRUCTION_31*sizeof(long));
553         } else {
554                 if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p &&
555                     current_thread_info()->utraps[0] > 1) {
556                         long *p = current_thread_info()->utraps;
557
558                         current_thread_info()->utraps =
559                                 kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long),
560                                         GFP_KERNEL);
561                         if (!current_thread_info()->utraps) {
562                                 current_thread_info()->utraps = p;
563                                 return -ENOMEM;
564                         }
565                         p[0]--;
566                         current_thread_info()->utraps[0] = 1;
567                         memcpy(current_thread_info()->utraps+1, p+1,
568                                UT_TRAP_INSTRUCTION_31*sizeof(long));
569                 }
570         }
571         if (old_p) {
572                 if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
573                         return -EFAULT;
574         }
575         if (old_d) {
576                 if (put_user(NULL, old_d))
577                         return -EFAULT;
578         }
579         current_thread_info()->utraps[type] = (long)new_p;
580
581         return 0;
582 }
583
584 long sparc_memory_ordering(unsigned long model, struct pt_regs *regs)
585 {
586         if (model >= 3)
587                 return -EINVAL;
588         regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
589         return 0;
590 }
591
592 asmlinkage long sys_rt_sigaction(int sig,
593                                  const struct sigaction __user *act,
594                                  struct sigaction __user *oact,
595                                  void __user *restorer,
596                                  size_t sigsetsize)
597 {
598         struct k_sigaction new_ka, old_ka;
599         int ret;
600
601         /* XXX: Don't preclude handling different sized sigset_t's.  */
602         if (sigsetsize != sizeof(sigset_t))
603                 return -EINVAL;
604
605         if (act) {
606                 new_ka.ka_restorer = restorer;
607                 if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
608                         return -EFAULT;
609         }
610
611         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
612
613         if (!ret && oact) {
614                 if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
615                         return -EFAULT;
616         }
617
618         return ret;
619 }
620
621 /* Invoked by rtrap code to update performance counters in
622  * user space.
623  */
624 asmlinkage void update_perfctrs(void)
625 {
626         unsigned long pic, tmp;
627
628         read_pic(pic);
629         tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
630         __put_user(tmp, current_thread_info()->user_cntd0);
631         tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
632         __put_user(tmp, current_thread_info()->user_cntd1);
633         reset_pic();
634 }
635
636 asmlinkage long sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
637 {
638         int err = 0;
639
640         switch(opcode) {
641         case PERFCTR_ON:
642                 current_thread_info()->pcr_reg = arg2;
643                 current_thread_info()->user_cntd0 = (u64 __user *) arg0;
644                 current_thread_info()->user_cntd1 = (u64 __user *) arg1;
645                 current_thread_info()->kernel_cntd0 =
646                         current_thread_info()->kernel_cntd1 = 0;
647                 write_pcr(arg2);
648                 reset_pic();
649                 set_thread_flag(TIF_PERFCTR);
650                 break;
651
652         case PERFCTR_OFF:
653                 err = -EINVAL;
654                 if (test_thread_flag(TIF_PERFCTR)) {
655                         current_thread_info()->user_cntd0 =
656                                 current_thread_info()->user_cntd1 = NULL;
657                         current_thread_info()->pcr_reg = 0;
658                         write_pcr(0);
659                         clear_thread_flag(TIF_PERFCTR);
660                         err = 0;
661                 }
662                 break;
663
664         case PERFCTR_READ: {
665                 unsigned long pic, tmp;
666
667                 if (!test_thread_flag(TIF_PERFCTR)) {
668                         err = -EINVAL;
669                         break;
670                 }
671                 read_pic(pic);
672                 tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
673                 err |= __put_user(tmp, current_thread_info()->user_cntd0);
674                 tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
675                 err |= __put_user(tmp, current_thread_info()->user_cntd1);
676                 reset_pic();
677                 break;
678         }
679
680         case PERFCTR_CLRPIC:
681                 if (!test_thread_flag(TIF_PERFCTR)) {
682                         err = -EINVAL;
683                         break;
684                 }
685                 current_thread_info()->kernel_cntd0 =
686                         current_thread_info()->kernel_cntd1 = 0;
687                 reset_pic();
688                 break;
689
690         case PERFCTR_SETPCR: {
691                 u64 __user *user_pcr = (u64 __user *)arg0;
692
693                 if (!test_thread_flag(TIF_PERFCTR)) {
694                         err = -EINVAL;
695                         break;
696                 }
697                 err |= __get_user(current_thread_info()->pcr_reg, user_pcr);
698                 write_pcr(current_thread_info()->pcr_reg);
699                 current_thread_info()->kernel_cntd0 =
700                         current_thread_info()->kernel_cntd1 = 0;
701                 reset_pic();
702                 break;
703         }
704
705         case PERFCTR_GETPCR: {
706                 u64 __user *user_pcr = (u64 __user *)arg0;
707
708                 if (!test_thread_flag(TIF_PERFCTR)) {
709                         err = -EINVAL;
710                         break;
711                 }
712                 err |= __put_user(current_thread_info()->pcr_reg, user_pcr);
713                 break;
714         }
715
716         default:
717                 err = -EINVAL;
718                 break;
719         };
720         return err;
721 }