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