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