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