sys_m68k.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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