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