xref: /openbmc/linux/arch/m68k/kernel/sys_m68k.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cae2e6ccSGreg Ungerer /*
3cae2e6ccSGreg Ungerer  * linux/arch/m68k/kernel/sys_m68k.c
4cae2e6ccSGreg Ungerer  *
5cae2e6ccSGreg Ungerer  * This file contains various random system calls that
6cae2e6ccSGreg Ungerer  * have a non-standard calling sequence on the Linux/m68k
7cae2e6ccSGreg Ungerer  * platform.
8cae2e6ccSGreg Ungerer  */
9cae2e6ccSGreg Ungerer 
10cae2e6ccSGreg Ungerer #include <linux/capability.h>
11cae2e6ccSGreg Ungerer #include <linux/errno.h>
12cae2e6ccSGreg Ungerer #include <linux/sched.h>
13cae2e6ccSGreg Ungerer #include <linux/mm.h>
14cae2e6ccSGreg Ungerer #include <linux/fs.h>
15cae2e6ccSGreg Ungerer #include <linux/smp.h>
16cae2e6ccSGreg Ungerer #include <linux/sem.h>
17cae2e6ccSGreg Ungerer #include <linux/msg.h>
18cae2e6ccSGreg Ungerer #include <linux/shm.h>
19cae2e6ccSGreg Ungerer #include <linux/stat.h>
20cae2e6ccSGreg Ungerer #include <linux/syscalls.h>
21cae2e6ccSGreg Ungerer #include <linux/mman.h>
22cae2e6ccSGreg Ungerer #include <linux/file.h>
23cae2e6ccSGreg Ungerer #include <linux/ipc.h>
24cae2e6ccSGreg Ungerer 
25cae2e6ccSGreg Ungerer #include <asm/setup.h>
267c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
27cae2e6ccSGreg Ungerer #include <asm/cachectl.h>
28cae2e6ccSGreg Ungerer #include <asm/traps.h>
29cae2e6ccSGreg Ungerer #include <asm/page.h>
30cae2e6ccSGreg Ungerer #include <asm/unistd.h>
31cae2e6ccSGreg Ungerer #include <asm/cacheflush.h>
32cae2e6ccSGreg Ungerer 
3366d857b0SGreg Ungerer #ifdef CONFIG_MMU
34cae2e6ccSGreg Ungerer 
35cae2e6ccSGreg Ungerer #include <asm/tlb.h>
36cae2e6ccSGreg Ungerer 
37cae2e6ccSGreg Ungerer asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
38cae2e6ccSGreg Ungerer 			     unsigned long error_code);
39cae2e6ccSGreg Ungerer 
sys_mmap2(unsigned long addr,unsigned long len,unsigned long prot,unsigned long flags,unsigned long fd,unsigned long pgoff)40cae2e6ccSGreg Ungerer asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
41cae2e6ccSGreg Ungerer 	unsigned long prot, unsigned long flags,
42cae2e6ccSGreg Ungerer 	unsigned long fd, unsigned long pgoff)
43cae2e6ccSGreg Ungerer {
44cae2e6ccSGreg Ungerer 	/*
45cae2e6ccSGreg Ungerer 	 * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
46cae2e6ccSGreg Ungerer 	 * so we need to shift the argument down by 1; m68k mmap64(3)
47cae2e6ccSGreg Ungerer 	 * (in libc) expects the last argument of mmap2 in 4Kb units.
48cae2e6ccSGreg Ungerer 	 */
49a90f590aSDominik Brodowski 	return ksys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
50cae2e6ccSGreg Ungerer }
51cae2e6ccSGreg Ungerer 
52cae2e6ccSGreg Ungerer /* Convert virtual (user) address VADDR to physical address PADDR */
53cae2e6ccSGreg Ungerer #define virt_to_phys_040(vaddr)						\
54cae2e6ccSGreg Ungerer ({									\
55cae2e6ccSGreg Ungerer   unsigned long _mmusr, _paddr;						\
56cae2e6ccSGreg Ungerer 									\
57cae2e6ccSGreg Ungerer   __asm__ __volatile__ (".chip 68040\n\t"				\
58cae2e6ccSGreg Ungerer 			"ptestr (%1)\n\t"				\
59cae2e6ccSGreg Ungerer 			"movec %%mmusr,%0\n\t"				\
60cae2e6ccSGreg Ungerer 			".chip 68k"					\
61cae2e6ccSGreg Ungerer 			: "=r" (_mmusr)					\
62cae2e6ccSGreg Ungerer 			: "a" (vaddr));					\
63cae2e6ccSGreg Ungerer   _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;		\
64cae2e6ccSGreg Ungerer   _paddr;								\
65cae2e6ccSGreg Ungerer })
66cae2e6ccSGreg Ungerer 
67cae2e6ccSGreg Ungerer static inline int
cache_flush_040(unsigned long addr,int scope,int cache,unsigned long len)68cae2e6ccSGreg Ungerer cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
69cae2e6ccSGreg Ungerer {
70cae2e6ccSGreg Ungerer   unsigned long paddr, i;
71cae2e6ccSGreg Ungerer 
72cae2e6ccSGreg Ungerer   switch (scope)
73cae2e6ccSGreg Ungerer     {
74cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_ALL:
75cae2e6ccSGreg Ungerer       switch (cache)
76cae2e6ccSGreg Ungerer 	{
77cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_DATA:
78cae2e6ccSGreg Ungerer 	  /* This nop is needed for some broken versions of the 68040.  */
79cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ ("nop\n\t"
80cae2e6ccSGreg Ungerer 				".chip 68040\n\t"
81cae2e6ccSGreg Ungerer 				"cpusha %dc\n\t"
82cae2e6ccSGreg Ungerer 				".chip 68k");
83cae2e6ccSGreg Ungerer 	  break;
84cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_INSN:
85cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ ("nop\n\t"
86cae2e6ccSGreg Ungerer 				".chip 68040\n\t"
87cae2e6ccSGreg Ungerer 				"cpusha %ic\n\t"
88cae2e6ccSGreg Ungerer 				".chip 68k");
89cae2e6ccSGreg Ungerer 	  break;
90cae2e6ccSGreg Ungerer 	default:
91cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_BOTH:
92cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ ("nop\n\t"
93cae2e6ccSGreg Ungerer 				".chip 68040\n\t"
94cae2e6ccSGreg Ungerer 				"cpusha %bc\n\t"
95cae2e6ccSGreg Ungerer 				".chip 68k");
96cae2e6ccSGreg Ungerer 	  break;
97cae2e6ccSGreg Ungerer 	}
98cae2e6ccSGreg Ungerer       break;
99cae2e6ccSGreg Ungerer 
100cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_LINE:
101cae2e6ccSGreg Ungerer       /* Find the physical address of the first mapped page in the
102cae2e6ccSGreg Ungerer 	 address range.  */
103cae2e6ccSGreg Ungerer       if ((paddr = virt_to_phys_040(addr))) {
104cae2e6ccSGreg Ungerer         paddr += addr & ~(PAGE_MASK | 15);
105cae2e6ccSGreg Ungerer         len = (len + (addr & 15) + 15) >> 4;
106cae2e6ccSGreg Ungerer       } else {
107cae2e6ccSGreg Ungerer 	unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
108cae2e6ccSGreg Ungerer 
109cae2e6ccSGreg Ungerer 	if (len <= tmp)
110cae2e6ccSGreg Ungerer 	  return 0;
111cae2e6ccSGreg Ungerer 	addr += tmp;
112cae2e6ccSGreg Ungerer 	len -= tmp;
113cae2e6ccSGreg Ungerer 	tmp = PAGE_SIZE;
114cae2e6ccSGreg Ungerer 	for (;;)
115cae2e6ccSGreg Ungerer 	  {
116cae2e6ccSGreg Ungerer 	    if ((paddr = virt_to_phys_040(addr)))
117cae2e6ccSGreg Ungerer 	      break;
118cae2e6ccSGreg Ungerer 	    if (len <= tmp)
119cae2e6ccSGreg Ungerer 	      return 0;
120cae2e6ccSGreg Ungerer 	    addr += tmp;
121cae2e6ccSGreg Ungerer 	    len -= tmp;
122cae2e6ccSGreg Ungerer 	  }
123cae2e6ccSGreg Ungerer 	len = (len + 15) >> 4;
124cae2e6ccSGreg Ungerer       }
125cae2e6ccSGreg Ungerer       i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
126cae2e6ccSGreg Ungerer       while (len--)
127cae2e6ccSGreg Ungerer 	{
128cae2e6ccSGreg Ungerer 	  switch (cache)
129cae2e6ccSGreg Ungerer 	    {
130cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_DATA:
131cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
132cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
133cae2e6ccSGreg Ungerer 				    "cpushl %%dc,(%0)\n\t"
134cae2e6ccSGreg Ungerer 				    ".chip 68k"
135cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
136cae2e6ccSGreg Ungerer 	      break;
137cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_INSN:
138cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
139cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
140cae2e6ccSGreg Ungerer 				    "cpushl %%ic,(%0)\n\t"
141cae2e6ccSGreg Ungerer 				    ".chip 68k"
142cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
143cae2e6ccSGreg Ungerer 	      break;
144cae2e6ccSGreg Ungerer 	    default:
145cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_BOTH:
146cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
147cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
148cae2e6ccSGreg Ungerer 				    "cpushl %%bc,(%0)\n\t"
149cae2e6ccSGreg Ungerer 				    ".chip 68k"
150cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
151cae2e6ccSGreg Ungerer 	      break;
152cae2e6ccSGreg Ungerer 	    }
153cae2e6ccSGreg Ungerer 	  if (!--i && len)
154cae2e6ccSGreg Ungerer 	    {
155cae2e6ccSGreg Ungerer 	      /*
156cae2e6ccSGreg Ungerer 	       * No need to page align here since it is done by
157cae2e6ccSGreg Ungerer 	       * virt_to_phys_040().
158cae2e6ccSGreg Ungerer 	       */
159cae2e6ccSGreg Ungerer 	      addr += PAGE_SIZE;
160cae2e6ccSGreg Ungerer 	      i = PAGE_SIZE / 16;
161cae2e6ccSGreg Ungerer 	      /* Recompute physical address when crossing a page
162cae2e6ccSGreg Ungerer 	         boundary. */
163cae2e6ccSGreg Ungerer 	      for (;;)
164cae2e6ccSGreg Ungerer 		{
165cae2e6ccSGreg Ungerer 		  if ((paddr = virt_to_phys_040(addr)))
166cae2e6ccSGreg Ungerer 		    break;
167cae2e6ccSGreg Ungerer 		  if (len <= i)
168cae2e6ccSGreg Ungerer 		    return 0;
169cae2e6ccSGreg Ungerer 		  len -= i;
170cae2e6ccSGreg Ungerer 		  addr += PAGE_SIZE;
171cae2e6ccSGreg Ungerer 		}
172cae2e6ccSGreg Ungerer 	    }
173cae2e6ccSGreg Ungerer 	  else
174cae2e6ccSGreg Ungerer 	    paddr += 16;
175cae2e6ccSGreg Ungerer 	}
176cae2e6ccSGreg Ungerer       break;
177cae2e6ccSGreg Ungerer 
178cae2e6ccSGreg Ungerer     default:
179cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_PAGE:
180cae2e6ccSGreg Ungerer       len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
181cae2e6ccSGreg Ungerer       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
182cae2e6ccSGreg Ungerer 	{
183cae2e6ccSGreg Ungerer 	  if (!(paddr = virt_to_phys_040(addr)))
184cae2e6ccSGreg Ungerer 	    continue;
185cae2e6ccSGreg Ungerer 	  switch (cache)
186cae2e6ccSGreg Ungerer 	    {
187cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_DATA:
188cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
189cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
190cae2e6ccSGreg Ungerer 				    "cpushp %%dc,(%0)\n\t"
191cae2e6ccSGreg Ungerer 				    ".chip 68k"
192cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
193cae2e6ccSGreg Ungerer 	      break;
194cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_INSN:
195cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
196cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
197cae2e6ccSGreg Ungerer 				    "cpushp %%ic,(%0)\n\t"
198cae2e6ccSGreg Ungerer 				    ".chip 68k"
199cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
200cae2e6ccSGreg Ungerer 	      break;
201cae2e6ccSGreg Ungerer 	    default:
202cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_BOTH:
203cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ ("nop\n\t"
204cae2e6ccSGreg Ungerer 				    ".chip 68040\n\t"
205cae2e6ccSGreg Ungerer 				    "cpushp %%bc,(%0)\n\t"
206cae2e6ccSGreg Ungerer 				    ".chip 68k"
207cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
208cae2e6ccSGreg Ungerer 	      break;
209cae2e6ccSGreg Ungerer 	    }
210cae2e6ccSGreg Ungerer 	}
211cae2e6ccSGreg Ungerer       break;
212cae2e6ccSGreg Ungerer     }
213cae2e6ccSGreg Ungerer   return 0;
214cae2e6ccSGreg Ungerer }
215cae2e6ccSGreg Ungerer 
216cae2e6ccSGreg Ungerer #define virt_to_phys_060(vaddr)				\
217cae2e6ccSGreg Ungerer ({							\
218cae2e6ccSGreg Ungerer   unsigned long paddr;					\
219cae2e6ccSGreg Ungerer   __asm__ __volatile__ (".chip 68060\n\t"		\
220cae2e6ccSGreg Ungerer 			"plpar (%0)\n\t"		\
221cae2e6ccSGreg Ungerer 			".chip 68k"			\
222cae2e6ccSGreg Ungerer 			: "=a" (paddr)			\
223cae2e6ccSGreg Ungerer 			: "0" (vaddr));			\
224cae2e6ccSGreg Ungerer   (paddr); /* XXX */					\
225cae2e6ccSGreg Ungerer })
226cae2e6ccSGreg Ungerer 
227cae2e6ccSGreg Ungerer static inline int
cache_flush_060(unsigned long addr,int scope,int cache,unsigned long len)228cae2e6ccSGreg Ungerer cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
229cae2e6ccSGreg Ungerer {
230cae2e6ccSGreg Ungerer   unsigned long paddr, i;
231cae2e6ccSGreg Ungerer 
232cae2e6ccSGreg Ungerer   /*
233cae2e6ccSGreg Ungerer    * 68060 manual says:
234cae2e6ccSGreg Ungerer    *  cpush %dc : flush DC, remains valid (with our %cacr setup)
235cae2e6ccSGreg Ungerer    *  cpush %ic : invalidate IC
236cae2e6ccSGreg Ungerer    *  cpush %bc : flush DC + invalidate IC
237cae2e6ccSGreg Ungerer    */
238cae2e6ccSGreg Ungerer   switch (scope)
239cae2e6ccSGreg Ungerer     {
240cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_ALL:
241cae2e6ccSGreg Ungerer       switch (cache)
242cae2e6ccSGreg Ungerer 	{
243cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_DATA:
244cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ (".chip 68060\n\t"
245cae2e6ccSGreg Ungerer 				"cpusha %dc\n\t"
246cae2e6ccSGreg Ungerer 				".chip 68k");
247cae2e6ccSGreg Ungerer 	  break;
248cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_INSN:
249cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ (".chip 68060\n\t"
250cae2e6ccSGreg Ungerer 				"cpusha %ic\n\t"
251cae2e6ccSGreg Ungerer 				".chip 68k");
252cae2e6ccSGreg Ungerer 	  break;
253cae2e6ccSGreg Ungerer 	default:
254cae2e6ccSGreg Ungerer 	case FLUSH_CACHE_BOTH:
255cae2e6ccSGreg Ungerer 	  __asm__ __volatile__ (".chip 68060\n\t"
256cae2e6ccSGreg Ungerer 				"cpusha %bc\n\t"
257cae2e6ccSGreg Ungerer 				".chip 68k");
258cae2e6ccSGreg Ungerer 	  break;
259cae2e6ccSGreg Ungerer 	}
260cae2e6ccSGreg Ungerer       break;
261cae2e6ccSGreg Ungerer 
262cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_LINE:
263cae2e6ccSGreg Ungerer       /* Find the physical address of the first mapped page in the
264cae2e6ccSGreg Ungerer 	 address range.  */
265cae2e6ccSGreg Ungerer       len += addr & 15;
266cae2e6ccSGreg Ungerer       addr &= -16;
267cae2e6ccSGreg Ungerer       if (!(paddr = virt_to_phys_060(addr))) {
268cae2e6ccSGreg Ungerer 	unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
269cae2e6ccSGreg Ungerer 
270cae2e6ccSGreg Ungerer 	if (len <= tmp)
271cae2e6ccSGreg Ungerer 	  return 0;
272cae2e6ccSGreg Ungerer 	addr += tmp;
273cae2e6ccSGreg Ungerer 	len -= tmp;
274cae2e6ccSGreg Ungerer 	tmp = PAGE_SIZE;
275cae2e6ccSGreg Ungerer 	for (;;)
276cae2e6ccSGreg Ungerer 	  {
277cae2e6ccSGreg Ungerer 	    if ((paddr = virt_to_phys_060(addr)))
278cae2e6ccSGreg Ungerer 	      break;
279cae2e6ccSGreg Ungerer 	    if (len <= tmp)
280cae2e6ccSGreg Ungerer 	      return 0;
281cae2e6ccSGreg Ungerer 	    addr += tmp;
282cae2e6ccSGreg Ungerer 	    len -= tmp;
283cae2e6ccSGreg Ungerer 	  }
284cae2e6ccSGreg Ungerer       }
285cae2e6ccSGreg Ungerer       len = (len + 15) >> 4;
286cae2e6ccSGreg Ungerer       i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
287cae2e6ccSGreg Ungerer       while (len--)
288cae2e6ccSGreg Ungerer 	{
289cae2e6ccSGreg Ungerer 	  switch (cache)
290cae2e6ccSGreg Ungerer 	    {
291cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_DATA:
292cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
293cae2e6ccSGreg Ungerer 				    "cpushl %%dc,(%0)\n\t"
294cae2e6ccSGreg Ungerer 				    ".chip 68k"
295cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
296cae2e6ccSGreg Ungerer 	      break;
297cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_INSN:
298cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
299cae2e6ccSGreg Ungerer 				    "cpushl %%ic,(%0)\n\t"
300cae2e6ccSGreg Ungerer 				    ".chip 68k"
301cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
302cae2e6ccSGreg Ungerer 	      break;
303cae2e6ccSGreg Ungerer 	    default:
304cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_BOTH:
305cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
306cae2e6ccSGreg Ungerer 				    "cpushl %%bc,(%0)\n\t"
307cae2e6ccSGreg Ungerer 				    ".chip 68k"
308cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
309cae2e6ccSGreg Ungerer 	      break;
310cae2e6ccSGreg Ungerer 	    }
311cae2e6ccSGreg Ungerer 	  if (!--i && len)
312cae2e6ccSGreg Ungerer 	    {
313cae2e6ccSGreg Ungerer 
314cae2e6ccSGreg Ungerer 	      /*
315cae2e6ccSGreg Ungerer 	       * We just want to jump to the first cache line
316cae2e6ccSGreg Ungerer 	       * in the next page.
317cae2e6ccSGreg Ungerer 	       */
318cae2e6ccSGreg Ungerer 	      addr += PAGE_SIZE;
319cae2e6ccSGreg Ungerer 	      addr &= PAGE_MASK;
320cae2e6ccSGreg Ungerer 
321cae2e6ccSGreg Ungerer 	      i = PAGE_SIZE / 16;
322cae2e6ccSGreg Ungerer 	      /* Recompute physical address when crossing a page
323cae2e6ccSGreg Ungerer 	         boundary. */
324cae2e6ccSGreg Ungerer 	      for (;;)
325cae2e6ccSGreg Ungerer 	        {
326cae2e6ccSGreg Ungerer 	          if ((paddr = virt_to_phys_060(addr)))
327cae2e6ccSGreg Ungerer 	            break;
328cae2e6ccSGreg Ungerer 	          if (len <= i)
329cae2e6ccSGreg Ungerer 	            return 0;
330cae2e6ccSGreg Ungerer 	          len -= i;
331cae2e6ccSGreg Ungerer 	          addr += PAGE_SIZE;
332cae2e6ccSGreg Ungerer 	        }
333cae2e6ccSGreg Ungerer 	    }
334cae2e6ccSGreg Ungerer 	  else
335cae2e6ccSGreg Ungerer 	    paddr += 16;
336cae2e6ccSGreg Ungerer 	}
337cae2e6ccSGreg Ungerer       break;
338cae2e6ccSGreg Ungerer 
339cae2e6ccSGreg Ungerer     default:
340cae2e6ccSGreg Ungerer     case FLUSH_SCOPE_PAGE:
341cae2e6ccSGreg Ungerer       len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
342cae2e6ccSGreg Ungerer       addr &= PAGE_MASK;	/* Workaround for bug in some
343cae2e6ccSGreg Ungerer 				   revisions of the 68060 */
344cae2e6ccSGreg Ungerer       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
345cae2e6ccSGreg Ungerer 	{
346cae2e6ccSGreg Ungerer 	  if (!(paddr = virt_to_phys_060(addr)))
347cae2e6ccSGreg Ungerer 	    continue;
348cae2e6ccSGreg Ungerer 	  switch (cache)
349cae2e6ccSGreg Ungerer 	    {
350cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_DATA:
351cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
352cae2e6ccSGreg Ungerer 				    "cpushp %%dc,(%0)\n\t"
353cae2e6ccSGreg Ungerer 				    ".chip 68k"
354cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
355cae2e6ccSGreg Ungerer 	      break;
356cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_INSN:
357cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
358cae2e6ccSGreg Ungerer 				    "cpushp %%ic,(%0)\n\t"
359cae2e6ccSGreg Ungerer 				    ".chip 68k"
360cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
361cae2e6ccSGreg Ungerer 	      break;
362cae2e6ccSGreg Ungerer 	    default:
363cae2e6ccSGreg Ungerer 	    case FLUSH_CACHE_BOTH:
364cae2e6ccSGreg Ungerer 	      __asm__ __volatile__ (".chip 68060\n\t"
365cae2e6ccSGreg Ungerer 				    "cpushp %%bc,(%0)\n\t"
366cae2e6ccSGreg Ungerer 				    ".chip 68k"
367cae2e6ccSGreg Ungerer 				    : : "a" (paddr));
368cae2e6ccSGreg Ungerer 	      break;
369cae2e6ccSGreg Ungerer 	    }
370cae2e6ccSGreg Ungerer 	}
371cae2e6ccSGreg Ungerer       break;
372cae2e6ccSGreg Ungerer     }
373cae2e6ccSGreg Ungerer   return 0;
374cae2e6ccSGreg Ungerer }
375cae2e6ccSGreg Ungerer 
376cae2e6ccSGreg Ungerer /* sys_cacheflush -- flush (part of) the processor cache.  */
377cae2e6ccSGreg Ungerer asmlinkage int
sys_cacheflush(unsigned long addr,int scope,int cache,unsigned long len)378cae2e6ccSGreg Ungerer sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
379cae2e6ccSGreg Ungerer {
380cae2e6ccSGreg Ungerer 	int ret = -EINVAL;
381cae2e6ccSGreg Ungerer 
382cae2e6ccSGreg Ungerer 	if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
383cae2e6ccSGreg Ungerer 	    cache & ~FLUSH_CACHE_BOTH)
384cae2e6ccSGreg Ungerer 		goto out;
385cae2e6ccSGreg Ungerer 
386cae2e6ccSGreg Ungerer 	if (scope == FLUSH_SCOPE_ALL) {
387cae2e6ccSGreg Ungerer 		/* Only the superuser may explicitly flush the whole cache. */
388cae2e6ccSGreg Ungerer 		ret = -EPERM;
389cae2e6ccSGreg Ungerer 		if (!capable(CAP_SYS_ADMIN))
390cae2e6ccSGreg Ungerer 			goto out;
391f829b4b2SLiam Howlett 
392f829b4b2SLiam Howlett 		mmap_read_lock(current->mm);
393cae2e6ccSGreg Ungerer 	} else {
394cd2567b6SDavidlohr Bueso 		struct vm_area_struct *vma;
395cd2567b6SDavidlohr Bueso 
396cd2567b6SDavidlohr Bueso 		/* Check for overflow.  */
397cd2567b6SDavidlohr Bueso 		if (addr + len < addr)
398cd2567b6SDavidlohr Bueso 			goto out;
399cd2567b6SDavidlohr Bueso 
400cae2e6ccSGreg Ungerer 		/*
401cae2e6ccSGreg Ungerer 		 * Verify that the specified address region actually belongs
402cae2e6ccSGreg Ungerer 		 * to this process.
403cae2e6ccSGreg Ungerer 		 */
404d8ed45c5SMichel Lespinasse 		mmap_read_lock(current->mm);
4053b93e042SLiam Howlett 		vma = vma_lookup(current->mm, addr);
4063b93e042SLiam Howlett 		if (!vma || addr + len > vma->vm_end)
407cd2567b6SDavidlohr Bueso 			goto out_unlock;
408cae2e6ccSGreg Ungerer 	}
409cae2e6ccSGreg Ungerer 
410cae2e6ccSGreg Ungerer 	if (CPU_IS_020_OR_030) {
411cae2e6ccSGreg Ungerer 		if (scope == FLUSH_SCOPE_LINE && len < 256) {
412cae2e6ccSGreg Ungerer 			unsigned long cacr;
413cae2e6ccSGreg Ungerer 			__asm__ ("movec %%cacr, %0" : "=r" (cacr));
414cae2e6ccSGreg Ungerer 			if (cache & FLUSH_CACHE_INSN)
415cae2e6ccSGreg Ungerer 				cacr |= 4;
416cae2e6ccSGreg Ungerer 			if (cache & FLUSH_CACHE_DATA)
417cae2e6ccSGreg Ungerer 				cacr |= 0x400;
418cae2e6ccSGreg Ungerer 			len >>= 2;
419cae2e6ccSGreg Ungerer 			while (len--) {
420cae2e6ccSGreg Ungerer 				__asm__ __volatile__ ("movec %1, %%caar\n\t"
421cae2e6ccSGreg Ungerer 						      "movec %0, %%cacr"
422cae2e6ccSGreg Ungerer 						      : /* no outputs */
423cae2e6ccSGreg Ungerer 						      : "r" (cacr), "r" (addr));
424cae2e6ccSGreg Ungerer 				addr += 4;
425cae2e6ccSGreg Ungerer 			}
426cae2e6ccSGreg Ungerer 		} else {
427cae2e6ccSGreg Ungerer 			/* Flush the whole cache, even if page granularity requested. */
428cae2e6ccSGreg Ungerer 			unsigned long cacr;
429cae2e6ccSGreg Ungerer 			__asm__ ("movec %%cacr, %0" : "=r" (cacr));
430cae2e6ccSGreg Ungerer 			if (cache & FLUSH_CACHE_INSN)
431cae2e6ccSGreg Ungerer 				cacr |= 8;
432cae2e6ccSGreg Ungerer 			if (cache & FLUSH_CACHE_DATA)
433cae2e6ccSGreg Ungerer 				cacr |= 0x800;
434cae2e6ccSGreg Ungerer 			__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
435cae2e6ccSGreg Ungerer 		}
436cae2e6ccSGreg Ungerer 		ret = 0;
437cd2567b6SDavidlohr Bueso 		goto out_unlock;
438cae2e6ccSGreg Ungerer 	} else {
439cae2e6ccSGreg Ungerer 	    /*
440cae2e6ccSGreg Ungerer 	     * 040 or 060: don't blindly trust 'scope', someone could
441cae2e6ccSGreg Ungerer 	     * try to flush a few megs of memory.
442cae2e6ccSGreg Ungerer 	     */
443cae2e6ccSGreg Ungerer 
444cae2e6ccSGreg Ungerer 	    if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
445cae2e6ccSGreg Ungerer 	        scope=FLUSH_SCOPE_PAGE;
446cae2e6ccSGreg Ungerer 	    if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
447cae2e6ccSGreg Ungerer 	        scope=FLUSH_SCOPE_ALL;
448cae2e6ccSGreg Ungerer 	    if (CPU_IS_040) {
449cae2e6ccSGreg Ungerer 		ret = cache_flush_040 (addr, scope, cache, len);
450cae2e6ccSGreg Ungerer 	    } else if (CPU_IS_060) {
451cae2e6ccSGreg Ungerer 		ret = cache_flush_060 (addr, scope, cache, len);
452cae2e6ccSGreg Ungerer 	    }
453cae2e6ccSGreg Ungerer 	}
454cd2567b6SDavidlohr Bueso out_unlock:
455d8ed45c5SMichel Lespinasse 	mmap_read_unlock(current->mm);
456cae2e6ccSGreg Ungerer out:
457cae2e6ccSGreg Ungerer 	return ret;
458cae2e6ccSGreg Ungerer }
459cae2e6ccSGreg Ungerer 
460cae2e6ccSGreg Ungerer /* This syscall gets its arguments in A0 (mem), D2 (oldval) and
461cae2e6ccSGreg Ungerer    D1 (newval).  */
462cae2e6ccSGreg Ungerer asmlinkage int
sys_atomic_cmpxchg_32(unsigned long newval,int oldval,int d3,int d4,int d5,unsigned long __user * mem)463cae2e6ccSGreg Ungerer sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
464cae2e6ccSGreg Ungerer 		      unsigned long __user * mem)
465cae2e6ccSGreg Ungerer {
466cae2e6ccSGreg Ungerer 	/* This was borrowed from ARM's implementation.  */
467cae2e6ccSGreg Ungerer 	for (;;) {
468cae2e6ccSGreg Ungerer 		struct mm_struct *mm = current->mm;
469cae2e6ccSGreg Ungerer 		pgd_t *pgd;
47060e50f34SMike Rapoport 		p4d_t *p4d;
47160e50f34SMike Rapoport 		pud_t *pud;
472cae2e6ccSGreg Ungerer 		pmd_t *pmd;
473cae2e6ccSGreg Ungerer 		pte_t *pte;
474cae2e6ccSGreg Ungerer 		spinlock_t *ptl;
475cae2e6ccSGreg Ungerer 		unsigned long mem_value;
476cae2e6ccSGreg Ungerer 
477d8ed45c5SMichel Lespinasse 		mmap_read_lock(mm);
478cae2e6ccSGreg Ungerer 		pgd = pgd_offset(mm, (unsigned long)mem);
479cae2e6ccSGreg Ungerer 		if (!pgd_present(*pgd))
480cae2e6ccSGreg Ungerer 			goto bad_access;
48160e50f34SMike Rapoport 		p4d = p4d_offset(pgd, (unsigned long)mem);
48260e50f34SMike Rapoport 		if (!p4d_present(*p4d))
48360e50f34SMike Rapoport 			goto bad_access;
48460e50f34SMike Rapoport 		pud = pud_offset(p4d, (unsigned long)mem);
48560e50f34SMike Rapoport 		if (!pud_present(*pud))
48660e50f34SMike Rapoport 			goto bad_access;
48760e50f34SMike Rapoport 		pmd = pmd_offset(pud, (unsigned long)mem);
488cae2e6ccSGreg Ungerer 		if (!pmd_present(*pmd))
489cae2e6ccSGreg Ungerer 			goto bad_access;
490cae2e6ccSGreg Ungerer 		pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
491*e67b37c3SHugh Dickins 		if (!pte)
492*e67b37c3SHugh Dickins 			goto bad_access;
493cae2e6ccSGreg Ungerer 		if (!pte_present(*pte) || !pte_dirty(*pte)
494cae2e6ccSGreg Ungerer 		    || !pte_write(*pte)) {
495cae2e6ccSGreg Ungerer 			pte_unmap_unlock(pte, ptl);
496cae2e6ccSGreg Ungerer 			goto bad_access;
497cae2e6ccSGreg Ungerer 		}
498cae2e6ccSGreg Ungerer 
4999e2760d1SAndreas Schwab 		/*
5009e2760d1SAndreas Schwab 		 * No need to check for EFAULT; we know that the page is
5019e2760d1SAndreas Schwab 		 * present and writable.
5029e2760d1SAndreas Schwab 		 */
5039e2760d1SAndreas Schwab 		__get_user(mem_value, mem);
504cae2e6ccSGreg Ungerer 		if (mem_value == oldval)
5059e2760d1SAndreas Schwab 			__put_user(newval, mem);
506cae2e6ccSGreg Ungerer 
507cae2e6ccSGreg Ungerer 		pte_unmap_unlock(pte, ptl);
508d8ed45c5SMichel Lespinasse 		mmap_read_unlock(mm);
509cae2e6ccSGreg Ungerer 		return mem_value;
510cae2e6ccSGreg Ungerer 
511cae2e6ccSGreg Ungerer 	      bad_access:
512d8ed45c5SMichel Lespinasse 		mmap_read_unlock(mm);
513cae2e6ccSGreg Ungerer 		/* This is not necessarily a bad access, we can get here if
514cae2e6ccSGreg Ungerer 		   a memory we're trying to write to should be copied-on-write.
515cae2e6ccSGreg Ungerer 		   Make the kernel do the necessary page stuff, then re-iterate.
516cae2e6ccSGreg Ungerer 		   Simulate a write access fault to do that.  */
517cae2e6ccSGreg Ungerer 		{
518cae2e6ccSGreg Ungerer 			/* The first argument of the function corresponds to
519cae2e6ccSGreg Ungerer 			   D1, which is the first field of struct pt_regs.  */
520cae2e6ccSGreg Ungerer 			struct pt_regs *fp = (struct pt_regs *)&newval;
521cae2e6ccSGreg Ungerer 
522cae2e6ccSGreg Ungerer 			/* '3' is an RMW flag.  */
523cae2e6ccSGreg Ungerer 			if (do_page_fault(fp, (unsigned long)mem, 3))
524cae2e6ccSGreg Ungerer 				/* If the do_page_fault() failed, we don't
525cae2e6ccSGreg Ungerer 				   have anything meaningful to return.
526cae2e6ccSGreg Ungerer 				   There should be a SIGSEGV pending for
527cae2e6ccSGreg Ungerer 				   the process.  */
528cae2e6ccSGreg Ungerer 				return 0xdeadbeef;
529cae2e6ccSGreg Ungerer 		}
530cae2e6ccSGreg Ungerer 	}
531cae2e6ccSGreg Ungerer }
532cae2e6ccSGreg Ungerer 
53366d857b0SGreg Ungerer #else
534cae2e6ccSGreg Ungerer 
535cae2e6ccSGreg Ungerer /* sys_cacheflush -- flush (part of) the processor cache.  */
536cae2e6ccSGreg Ungerer asmlinkage int
sys_cacheflush(unsigned long addr,int scope,int cache,unsigned long len)537cae2e6ccSGreg Ungerer sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
538cae2e6ccSGreg Ungerer {
539cae2e6ccSGreg Ungerer 	flush_cache_all();
540cae2e6ccSGreg Ungerer 	return 0;
541cae2e6ccSGreg Ungerer }
542cae2e6ccSGreg Ungerer 
543cae2e6ccSGreg Ungerer /* This syscall gets its arguments in A0 (mem), D2 (oldval) and
544cae2e6ccSGreg Ungerer    D1 (newval).  */
545cae2e6ccSGreg Ungerer asmlinkage int
sys_atomic_cmpxchg_32(unsigned long newval,int oldval,int d3,int d4,int d5,unsigned long __user * mem)546cae2e6ccSGreg Ungerer sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
547cae2e6ccSGreg Ungerer 		      unsigned long __user * mem)
548cae2e6ccSGreg Ungerer {
549cae2e6ccSGreg Ungerer 	struct mm_struct *mm = current->mm;
550cae2e6ccSGreg Ungerer 	unsigned long mem_value;
551cae2e6ccSGreg Ungerer 
552d8ed45c5SMichel Lespinasse 	mmap_read_lock(mm);
553cae2e6ccSGreg Ungerer 
554cae2e6ccSGreg Ungerer 	mem_value = *mem;
555cae2e6ccSGreg Ungerer 	if (mem_value == oldval)
556cae2e6ccSGreg Ungerer 		*mem = newval;
557cae2e6ccSGreg Ungerer 
558d8ed45c5SMichel Lespinasse 	mmap_read_unlock(mm);
559cae2e6ccSGreg Ungerer 	return mem_value;
560cae2e6ccSGreg Ungerer }
561cae2e6ccSGreg Ungerer 
562cae2e6ccSGreg Ungerer #endif /* CONFIG_MMU */
563cae2e6ccSGreg Ungerer 
sys_getpagesize(void)564cae2e6ccSGreg Ungerer asmlinkage int sys_getpagesize(void)
565cae2e6ccSGreg Ungerer {
566cae2e6ccSGreg Ungerer 	return PAGE_SIZE;
567cae2e6ccSGreg Ungerer }
568cae2e6ccSGreg Ungerer 
sys_get_thread_area(void)569cae2e6ccSGreg Ungerer asmlinkage unsigned long sys_get_thread_area(void)
570cae2e6ccSGreg Ungerer {
571cae2e6ccSGreg Ungerer 	return current_thread_info()->tp_value;
572cae2e6ccSGreg Ungerer }
573cae2e6ccSGreg Ungerer 
sys_set_thread_area(unsigned long tp)574cae2e6ccSGreg Ungerer asmlinkage int sys_set_thread_area(unsigned long tp)
575cae2e6ccSGreg Ungerer {
576cae2e6ccSGreg Ungerer 	current_thread_info()->tp_value = tp;
577cae2e6ccSGreg Ungerer 	return 0;
578cae2e6ccSGreg Ungerer }
579cae2e6ccSGreg Ungerer 
sys_atomic_barrier(void)580cae2e6ccSGreg Ungerer asmlinkage int sys_atomic_barrier(void)
581cae2e6ccSGreg Ungerer {
582cae2e6ccSGreg Ungerer 	/* no code needed for uniprocs */
583cae2e6ccSGreg Ungerer 	return 0;
584cae2e6ccSGreg Ungerer }
585