~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/arch/m68k/kernel/sys_m68k.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/arch/m68k/kernel/sys_m68k.c
  3  *
  4  * This file contains various random system calls that
  5  * have a non-standard calling sequence on the Linux/m68k
  6  * platform.
  7  */
  8 
  9 #include <linux/errno.h>
 10 #include <linux/sched.h>
 11 #include <linux/mm.h>
 12 #include <linux/smp.h>
 13 #include <linux/smp_lock.h>
 14 #include <linux/sem.h>
 15 #include <linux/msg.h>
 16 #include <linux/shm.h>
 17 #include <linux/stat.h>
 18 #include <linux/mman.h>
 19 #include <linux/file.h>
 20 #include <linux/utsname.h>
 21 
 22 #include <asm/setup.h>
 23 #include <asm/uaccess.h>
 24 #include <asm/cachectl.h>
 25 #include <asm/traps.h>
 26 #include <asm/ipc.h>
 27 #include <asm/page.h>
 28 
 29 /*
 30  * sys_pipe() is the normal C calling standard for creating
 31  * a pipe. It's not the way unix traditionally does this, though.
 32  */
 33 asmlinkage int sys_pipe(unsigned long * fildes)
 34 {
 35         int fd[2];
 36         int error;
 37 
 38         error = do_pipe(fd);
 39         if (!error) {
 40                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
 41                         error = -EFAULT;
 42         }
 43         return error;
 44 }
 45 
 46 /* common code for old and new mmaps */
 47 static inline long do_mmap2(
 48         unsigned long addr, unsigned long len,
 49         unsigned long prot, unsigned long flags,
 50         unsigned long fd, unsigned long pgoff)
 51 {
 52         int error = -EBADF;
 53         struct file * file = NULL;
 54 
 55         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 56         if (!(flags & MAP_ANONYMOUS)) {
 57                 file = fget(fd);
 58                 if (!file)
 59                         goto out;
 60         }
 61 
 62         down(&current->mm->mmap_sem);
 63         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 64         up(&current->mm->mmap_sem);
 65 
 66         if (file)
 67                 fput(file);
 68 out:
 69         return error;
 70 }
 71 
 72 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
 73         unsigned long prot, unsigned long flags,
 74         unsigned long fd, unsigned long pgoff)
 75 {
 76         return do_mmap2(addr, len, prot, flags, fd, pgoff);
 77 }
 78 
 79 /*
 80  * Perform the select(nd, in, out, ex, tv) and mmap() system
 81  * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
 82  * handle more than 4 system call parameters, so these system calls
 83  * used a memory block for parameter passing..
 84  */
 85 
 86 struct mmap_arg_struct {
 87         unsigned long addr;
 88         unsigned long len;
 89         unsigned long prot;
 90         unsigned long flags;
 91         unsigned long fd;
 92         unsigned long offset;
 93 };
 94 
 95 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
 96 {
 97         struct mmap_arg_struct a;
 98         int error = -EFAULT;
 99 
100         if (copy_from_user(&a, arg, sizeof(a)))
101                 goto out;
102 
103         error = -EINVAL;
104         if (a.offset & ~PAGE_MASK)
105                 goto out;
106 
107         a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
108 
109         error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
110 out:
111         return error;
112 }
113 
114 #if 0
115 struct mmap_arg_struct64 {
116         __u32 addr;
117         __u32 len;
118         __u32 prot;
119         __u32 flags;
120         __u64 offset; /* 64 bits */
121         __u32 fd;
122 };
123 
124 asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg)
125 {
126         int error = -EFAULT;
127         struct file * file = NULL;
128         struct mmap_arg_struct64 a;
129         unsigned long pgoff;
130 
131         if (copy_from_user(&a, arg, sizeof(a)))
132                 return -EFAULT;
133 
134         if ((long)a.offset & ~PAGE_MASK)
135                 return -EINVAL;
136 
137         pgoff = a.offset >> PAGE_SHIFT;
138         if ((a.offset >> PAGE_SHIFT) != pgoff)
139                 return -EINVAL;
140 
141         if (!(a.flags & MAP_ANONYMOUS)) {
142                 error = -EBADF;
143                 file = fget(a.fd);
144                 if (!file)
145                         goto out;
146         }
147         a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
148 
149         down(&current->mm->mmap_sem);
150         error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
151         up(&current->mm->mmap_sem);
152         if (file)
153                 fput(file);
154 out:
155         return error;
156 }
157 #endif
158 
159 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
160 
161 struct sel_arg_struct {
162         unsigned long n;
163         fd_set *inp, *outp, *exp;
164         struct timeval *tvp;
165 };
166 
167 asmlinkage int old_select(struct sel_arg_struct *arg)
168 {
169         struct sel_arg_struct a;
170 
171         if (copy_from_user(&a, arg, sizeof(a)))
172                 return -EFAULT;
173         /* sys_select() does the appropriate kernel locking */
174         return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
175 }
176 
177 /*
178  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
179  *
180  * This is really horribly ugly.
181  */
182 asmlinkage int sys_ipc (uint call, int first, int second,
183                         int third, void *ptr, long fifth)
184 {
185         int version, ret;
186 
187         version = call >> 16; /* hack for backward compatibility */
188         call &= 0xffff;
189 
190         if (call <= SEMCTL)
191                 switch (call) {
192                 case SEMOP:
193                         return sys_semop (first, (struct sembuf *)ptr, second);
194                 case SEMGET:
195                         return sys_semget (first, second, third);
196                 case SEMCTL: {
197                         union semun fourth;
198                         if (!ptr)
199                                 return -EINVAL;
200                         if (get_user(fourth.__pad, (void **) ptr))
201                                 return -EFAULT;
202                         return sys_semctl (first, second, third, fourth);
203                         }
204                 default:
205                         return -EINVAL;
206                 }
207         if (call <= MSGCTL) 
208                 switch (call) {
209                 case MSGSND:
210                         return sys_msgsnd (first, (struct msgbuf *) ptr, 
211                                           second, third);
212                 case MSGRCV:
213                         switch (version) {
214                         case 0: {
215                                 struct ipc_kludge tmp;
216                                 if (!ptr)
217                                         return -EINVAL;
218                                 if (copy_from_user (&tmp,
219                                                     (struct ipc_kludge *)ptr,
220                                                     sizeof (tmp)))
221                                         return -EFAULT;
222                                 return sys_msgrcv (first, tmp.msgp, second,
223                                                    tmp.msgtyp, third);
224                                 }
225                         default:
226                                 return sys_msgrcv (first,
227                                                    (struct msgbuf *) ptr,
228                                                    second, fifth, third);
229                         }
230                 case MSGGET:
231                         return sys_msgget ((key_t) first, second);
232                 case MSGCTL:
233                         return sys_msgctl (first, second,
234                                            (struct msqid_ds *) ptr);
235                 default:
236                         return -EINVAL;
237                 }
238         if (call <= SHMCTL) 
239                 switch (call) {
240                 case SHMAT:
241                         switch (version) {
242                         default: {
243                                 ulong raddr;
244                                 ret = sys_shmat (first, (char *) ptr,
245                                                  second, &raddr);
246                                 if (ret)
247                                         return ret;
248                                 return put_user (raddr, (ulong *) third);
249                         }
250                         }
251                 case SHMDT: 
252                         return sys_shmdt ((char *)ptr);
253                 case SHMGET:
254                         return sys_shmget (first, second, third);
255                 case SHMCTL:
256                         return sys_shmctl (first, second,
257                                            (struct shmid_ds *) ptr);
258                 default:
259                         return -EINVAL;
260                 }
261 
262         return -EINVAL;
263 }
264 
265 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
266 {
267   return -ENOSYS;
268 }
269 
270 /* Convert virtual address VADDR to physical address PADDR */
271 #define virt_to_phys_040(vaddr)                                         \
272 ({                                                                      \
273   unsigned long _mmusr, _paddr;                                         \
274                                                                         \
275   __asm__ __volatile__ (".chip 68040\n\t"                               \
276                         "ptestr (%1)\n\t"                               \
277                         "movec %%mmusr,%0\n\t"                          \
278                         ".chip 68k"                                     \
279                         : "=r" (_mmusr)                                 \
280                         : "a" (vaddr));                                 \
281   _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;             \
282   _paddr;                                                               \
283 })
284 
285 static inline int
286 cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
287 {
288   unsigned long paddr, i;
289 
290   switch (scope)
291     {
292     case FLUSH_SCOPE_ALL:
293       switch (cache)
294         {
295         case FLUSH_CACHE_DATA:
296           /* This nop is needed for some broken versions of the 68040.  */
297           __asm__ __volatile__ ("nop\n\t"
298                                 ".chip 68040\n\t"
299                                 "cpusha %dc\n\t"
300                                 ".chip 68k");
301           break;
302         case FLUSH_CACHE_INSN:
303           __asm__ __volatile__ ("nop\n\t"
304                                 ".chip 68040\n\t"
305                                 "cpusha %ic\n\t"
306                                 ".chip 68k");
307           break;
308         default:
309         case FLUSH_CACHE_BOTH:
310           __asm__ __volatile__ ("nop\n\t"
311                                 ".chip 68040\n\t"
312                                 "cpusha %bc\n\t"
313                                 ".chip 68k");
314           break;
315         }
316       break;
317 
318     case FLUSH_SCOPE_LINE:
319       /* Find the physical address of the first mapped page in the
320          address range.  */
321       if ((paddr = virt_to_phys_040(addr))) {
322         paddr += addr & ~(PAGE_MASK | 15);
323         len = (len + (addr & 15) + 15) >> 4;
324       } else {
325         unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
326 
327         if (len <= tmp)
328           return 0;
329         addr += tmp;
330         len -= tmp;
331         tmp = PAGE_SIZE;
332         for (;;)
333           {
334             if ((paddr = virt_to_phys_040(addr)))
335               break;
336             if (len <= tmp)
337               return 0;
338             addr += tmp;
339             len -= tmp;
340           }
341         len = (len + 15) >> 4;
342       }
343       i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
344       while (len--)
345         {
346           switch (cache)
347             {
348             case FLUSH_CACHE_DATA:
349               __asm__ __volatile__ ("nop\n\t"
350                                     ".chip 68040\n\t"
351                                     "cpushl %%dc,(%0)\n\t"
352                                     ".chip 68k"
353                                     : : "a" (paddr));
354               break;
355             case FLUSH_CACHE_INSN:
356               __asm__ __volatile__ ("nop\n\t"
357                                     ".chip 68040\n\t"
358                                     "cpushl %%ic,(%0)\n\t"
359                                     ".chip 68k"
360                                     : : "a" (paddr));
361               break;
362             default:
363             case FLUSH_CACHE_BOTH:
364               __asm__ __volatile__ ("nop\n\t"
365                                     ".chip 68040\n\t"
366                                     "cpushl %%bc,(%0)\n\t"
367                                     ".chip 68k"
368                                     : : "a" (paddr));
369               break;
370             }
371           if (!--i && len)
372             {
373               /*
374                * No need to page align here since it is done by
375                * virt_to_phys_040().
376                */
377               addr += PAGE_SIZE;
378               i = PAGE_SIZE / 16;
379               /* Recompute physical address when crossing a page
380                  boundary. */
381               for (;;)
382                 {
383                   if ((paddr = virt_to_phys_040(addr)))
384                     break;
385                   if (len <= i)
386                     return 0;
387                   len -= i;
388                   addr += PAGE_SIZE;
389                 }
390             }
391           else
392             paddr += 16;
393         }
394       break;
395 
396     default:
397     case FLUSH_SCOPE_PAGE:
398       len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
399       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
400         {
401           if (!(paddr = virt_to_phys_040(addr)))
402             continue;
403           switch (cache)
404             {
405             case FLUSH_CACHE_DATA:
406               __asm__ __volatile__ ("nop\n\t"
407                                     ".chip 68040\n\t"
408                                     "cpushp %%dc,(%0)\n\t"
409                                     ".chip 68k"
410                                     : : "a" (paddr));
411               break;
412             case FLUSH_CACHE_INSN:
413               __asm__ __volatile__ ("nop\n\t"
414                                     ".chip 68040\n\t"
415                                     "cpushp %%ic,(%0)\n\t"
416                                     ".chip 68k"
417                                     : : "a" (paddr));
418               break;
419             default:
420             case FLUSH_CACHE_BOTH:
421               __asm__ __volatile__ ("nop\n\t"
422                                     ".chip 68040\n\t"
423                                     "cpushp %%bc,(%0)\n\t"
424                                     ".chip 68k"
425                                     : : "a" (paddr));
426               break;
427             }
428         }
429       break;
430     }
431   return 0;
432 }
433 
434 #define virt_to_phys_060(vaddr)                         \
435 ({                                                      \
436   unsigned long paddr;                                  \
437   __asm__ __volatile__ (".chip 68060\n\t"               \
438                         "plpar (%0)\n\t"                \
439                         ".chip 68k"                     \
440                         : "=a" (paddr)                  \
441                         : "" (vaddr));                 \
442   (paddr); /* XXX */                                    \
443 })
444 
445 static inline int
446 cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
447 {
448   unsigned long paddr, i;
449 
450   switch (scope)
451     {
452     case FLUSH_SCOPE_ALL:
453       switch (cache)
454         {
455         case FLUSH_CACHE_DATA:
456           __asm__ __volatile__ (".chip 68060\n\t"
457                                 "cpusha %dc\n\t"
458                                 "cinva %dc\n\t"
459                                 ".chip 68k");
460           break;
461         case FLUSH_CACHE_INSN:
462           __asm__ __volatile__ (".chip 68060\n\t"
463                                 "cpusha %ic\n\t"
464                                 "cinva %ic\n\t"
465                                 ".chip 68k");
466           break;
467         default:
468         case FLUSH_CACHE_BOTH:
469           __asm__ __volatile__ (".chip 68060\n\t"
470                                 "cpusha %bc\n\t"
471                                 "cinva %bc\n\t"
472                                 ".chip 68k");
473           break;
474         }
475       break;
476 
477     case FLUSH_SCOPE_LINE:
478       /* Find the physical address of the first mapped page in the
479          address range.  */
480       len += addr & 15;
481       addr &= -16;
482       if (!(paddr = virt_to_phys_060(addr))) {
483         unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
484 
485         if (len <= tmp)
486           return 0;
487         addr += tmp;
488         len -= tmp;
489         tmp = PAGE_SIZE;
490         for (;;)
491           {
492             if ((paddr = virt_to_phys_060(addr)))
493               break;
494             if (len <= tmp)
495               return 0;
496             addr += tmp;
497             len -= tmp;
498           }
499       }
500       len = (len + 15) >> 4;
501       i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
502       while (len--)
503         {
504           switch (cache)
505             {
506             case FLUSH_CACHE_DATA:
507               __asm__ __volatile__ (".chip 68060\n\t"
508                                     "cpushl %%dc,(%0)\n\t"
509                                     "cinvl %%dc,(%0)\n\t"
510                                     ".chip 68k"
511                                     : : "a" (paddr));
512               break;
513             case FLUSH_CACHE_INSN:
514               __asm__ __volatile__ (".chip 68060\n\t"
515                                     "cpushl %%ic,(%0)\n\t"
516                                     "cinvl %%ic,(%0)\n\t"
517                                     ".chip 68k"
518                                     : : "a" (paddr));
519               break;
520             default:
521             case FLUSH_CACHE_BOTH:
522               __asm__ __volatile__ (".chip 68060\n\t"
523                                     "cpushl %%bc,(%0)\n\t"
524                                     "cinvl %%bc,(%0)\n\t"
525                                     ".chip 68k"
526                                     : : "a" (paddr));
527               break;
528             }
529           if (!--i && len)
530             {
531 
532               /*
533                * We just want to jump to the first cache line
534                * in the next page.
535                */
536               addr += PAGE_SIZE;
537               addr &= PAGE_MASK;
538 
539               i = PAGE_SIZE / 16;
540               /* Recompute physical address when crossing a page
541                  boundary. */
542               for (;;)
543                 {
544                   if ((paddr = virt_to_phys_060(addr)))
545                     break;
546                   if (len <= i)
547                     return 0;
548                   len -= i;
549                   addr += PAGE_SIZE;
550                 }
551             }
552           else
553             paddr += 16;
554         }
555       break;
556 
557     default:
558     case FLUSH_SCOPE_PAGE:
559       len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
560       addr &= PAGE_MASK;        /* Workaround for bug in some
561                                    revisions of the 68060 */
562       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
563         {
564           if (!(paddr = virt_to_phys_060(addr)))
565             continue;
566           switch (cache)
567             {
568             case FLUSH_CACHE_DATA:
569               __asm__ __volatile__ (".chip 68060\n\t"
570                                     "cpushp %%dc,(%0)\n\t"
571                                     "cinvp %%dc,(%0)\n\t"
572                                     ".chip 68k"
573                                     : : "a" (paddr));
574               break;
575             case FLUSH_CACHE_INSN:
576               __asm__ __volatile__ (".chip 68060\n\t"
577                                     "cpushp %%ic,(%0)\n\t"
578                                     "cinvp %%ic,(%0)\n\t"
579                                     ".chip 68k"
580                                     : : "a" (paddr));
581               break;
582             default:
583             case FLUSH_CACHE_BOTH:
584               __asm__ __volatile__ (".chip 68060\n\t"
585                                     "cpushp %%bc,(%0)\n\t"
586                                     "cinvp %%bc,(%0)\n\t"
587                                     ".chip 68k"
588                                     : : "a" (paddr));
589               break;
590             }
591         }
592       break;
593     }
594   return 0;
595 }
596 
597 /* sys_cacheflush -- flush (part of) the processor cache.  */
598 asmlinkage int
599 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
600 {
601         struct vm_area_struct *vma;
602         int ret = -EINVAL;
603 
604         lock_kernel();
605         if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
606             cache & ~FLUSH_CACHE_BOTH)
607                 goto out;
608 
609         if (scope == FLUSH_SCOPE_ALL) {
610                 /* Only the superuser may flush the whole cache. */
611                 ret = -EPERM;
612                 if (!capable(CAP_SYS_ADMIN))
613                         goto out;
614         } else {
615                 /* Verify that the specified address region actually belongs to
616                  * this process.
617                  */
618                 vma = find_vma (current->mm, addr);
619                 ret = -EINVAL;
620                 /* Check for overflow.  */
621                 if (addr + len < addr)
622                         goto out;
623                 if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
624                         goto out;
625         }
626 
627         if (CPU_IS_020_OR_030) {
628                 if (scope == FLUSH_SCOPE_LINE && len < 256) {
629                         unsigned long cacr;
630                         __asm__ ("movec %%cacr, %0" : "=r" (cacr));
631                         if (cache & FLUSH_CACHE_INSN)
632                                 cacr |= 4;
633                         if (cache & FLUSH_CACHE_DATA)
634                                 cacr |= 0x400;
635                         len >>= 2;
636                         while (len--) {
637                                 __asm__ __volatile__ ("movec %1, %%caar\n\t"
638                                                       "movec %0, %%cacr"
639                                                       : /* no outputs */
640                                                       : "r" (cacr), "r" (addr));
641                                 addr += 4;
642                         }
643                 } else {
644                         /* Flush the whole cache, even if page granularity requested. */
645                         unsigned long cacr;
646                         __asm__ ("movec %%cacr, %0" : "=r" (cacr));
647                         if (cache & FLUSH_CACHE_INSN)
648                                 cacr |= 8;
649                         if (cache & FLUSH_CACHE_DATA)
650                                 cacr |= 0x800;
651                         __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
652                 }
653                 ret = 0;
654                 goto out;
655         } else if (CPU_IS_040) {
656                 ret = cache_flush_040 (addr, scope, cache, len);
657         } else if (CPU_IS_060) {
658                 ret = cache_flush_060 (addr, scope, cache, len);
659         }
660 out:
661         unlock_kernel();
662         return ret;
663 }
664 
665 asmlinkage int sys_getpagesize(void)
666 {
667         return PAGE_SIZE;
668 }
669 
670 /*
671  * Old cruft
672  */
673 asmlinkage int sys_pause(void)
674 {
675         current->state = TASK_INTERRUPTIBLE;
676         schedule();
677         return -ERESTARTNOHAND;
678 }
679 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.