// SPDX-License-Identifier: GPL-2.0 /* * linux/arch/m68k/kernel/sys_m68k.c * * This file contains various random system calls that * have a non-standard calling sequence on the Linux/m68k * platform.
*/
asmlinkage long sys_mmap2(unsignedlong addr, unsignedlong len, unsignedlong prot, unsignedlong flags, unsignedlong fd, unsignedlong pgoff)
{ /* * This is wrong for sun3 - there PAGE_SIZE is 8Kb, * so we need to shift the argument down by 1; m68k mmap64(3) * (in libc) expects the last argument of mmap2 in 4Kb units.
*/ return ksys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
}
case FLUSH_SCOPE_LINE: /* Find the physical address of the first mapped page in the
address range. */
len += addr & 15;
addr &= -16; if (!(paddr = virt_to_phys_060(addr))) { unsignedlong tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
if (len <= tmp) return 0;
addr += tmp;
len -= tmp;
tmp = PAGE_SIZE; for (;;)
{ if ((paddr = virt_to_phys_060(addr))) break; if (len <= tmp) return 0;
addr += tmp;
len -= tmp;
}
}
len = (len + 15) >> 4;
i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; while (len--)
{ switch (cache)
{ case FLUSH_CACHE_DATA:
__asm__ __volatile__ (".chip 68060\n\t" "cpushl %%dc,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break; case FLUSH_CACHE_INSN:
__asm__ __volatile__ (".chip 68060\n\t" "cpushl %%ic,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH:
__asm__ __volatile__ (".chip 68060\n\t" "cpushl %%bc,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break;
} if (!--i && len)
{
/* * We just want to jump to the first cache line * in the next page.
*/
addr += PAGE_SIZE;
addr &= PAGE_MASK;
i = PAGE_SIZE / 16; /* Recompute physical address when crossing a page
boundary. */ for (;;)
{ if ((paddr = virt_to_phys_060(addr))) break; if (len <= i) return 0;
len -= i;
addr += PAGE_SIZE;
}
} else
paddr += 16;
} break;
default: case FLUSH_SCOPE_PAGE:
len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
addr &= PAGE_MASK; /* Workaround for bug in some
revisions of the 68060 */ for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
{ if (!(paddr = virt_to_phys_060(addr))) continue; switch (cache)
{ case FLUSH_CACHE_DATA:
__asm__ __volatile__ (".chip 68060\n\t" "cpushp %%dc,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break; case FLUSH_CACHE_INSN:
__asm__ __volatile__ (".chip 68060\n\t" "cpushp %%ic,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH:
__asm__ __volatile__ (".chip 68060\n\t" "cpushp %%bc,(%0)\n\t" ".chip 68k"
: : "a" (paddr)); break;
}
} break;
} return 0;
}
/* sys_cacheflush -- flush (part of) the processor cache. */
asmlinkage int
sys_cacheflush (unsignedlong addr, int scope, int cache, unsignedlong len)
{ int ret = -EINVAL;
/* Check for overflow. */ if (addr + len < addr) goto out;
/* * Verify that the specified address region actually belongs * to this process.
*/
mmap_read_lock(current->mm);
vma = vma_lookup(current->mm, addr); if (!vma || addr + len > vma->vm_end) goto out_unlock;
}
if (CPU_IS_020_OR_030) { if (scope == FLUSH_SCOPE_LINE && len < 256) { unsignedlong cacr;
__asm__ ("movec %%cacr, %0" : "=r" (cacr)); if (cache & FLUSH_CACHE_INSN)
cacr |= 4; if (cache & FLUSH_CACHE_DATA)
cacr |= 0x400;
len >>= 2; while (len--) {
__asm__ __volatile__ ("movec %1, %%caar\n\t" "movec %0, %%cacr"
: /* no outputs */
: "r" (cacr), "r" (addr));
addr += 4;
}
} else { /* Flush the whole cache, even if page granularity requested. */ unsignedlong cacr;
__asm__ ("movec %%cacr, %0" : "=r" (cacr)); if (cache & FLUSH_CACHE_INSN)
cacr |= 8; if (cache & FLUSH_CACHE_DATA)
cacr |= 0x800;
__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
}
ret = 0; goto out_unlock;
} else { /* * 040 or 060: don't blindly trust 'scope', someone could * try to flush a few megs of memory.
*/
if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
scope=FLUSH_SCOPE_PAGE; if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
scope=FLUSH_SCOPE_ALL; if (CPU_IS_040) {
ret = cache_flush_040 (addr, scope, cache, len);
} elseif (CPU_IS_060) {
ret = cache_flush_060 (addr, scope, cache, len);
}
}
out_unlock:
mmap_read_unlock(current->mm);
out: return ret;
}
/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
D1 (newval). */
asmlinkage int
sys_atomic_cmpxchg_32(unsignedlong newval, int oldval, int d3, int d4, int d5, unsignedlong __user * mem)
{ /* This was borrowed from ARM's implementation. */ for (;;) { struct mm_struct *mm = current->mm;
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
spinlock_t *ptl; unsignedlong mem_value;
mmap_read_lock(mm);
pgd = pgd_offset(mm, (unsignedlong)mem); if (!pgd_present(*pgd)) goto bad_access;
p4d = p4d_offset(pgd, (unsignedlong)mem); if (!p4d_present(*p4d)) goto bad_access;
pud = pud_offset(p4d, (unsignedlong)mem); if (!pud_present(*pud)) goto bad_access;
pmd = pmd_offset(pud, (unsignedlong)mem); if (!pmd_present(*pmd)) goto bad_access;
pte = pte_offset_map_lock(mm, pmd, (unsignedlong)mem, &ptl); if (!pte) goto bad_access; if (!pte_present(*pte) || !pte_dirty(*pte)
|| !pte_write(*pte)) {
pte_unmap_unlock(pte, ptl); goto bad_access;
}
/* * No need to check for EFAULT; we know that the page is * present and writable.
*/
__get_user(mem_value, mem); if (mem_value == oldval)
__put_user(newval, mem);
bad_access:
mmap_read_unlock(mm); /* This is not necessarily a bad access, we can get here if a memory we're trying to write to should be copied-on-write. Make the kernel do the necessary page stuff, then re-iterate.
Simulate a write access fault to do that. */
{ /* The first argument of the function corresponds to
D1, which is the first field of struct pt_regs. */ struct pt_regs *fp = (struct pt_regs *)&newval;
/* '3' is an RMW flag. */ if (do_page_fault(fp, (unsignedlong)mem, 3)) /* If the do_page_fault() failed, we don't have anything meaningful to return. There should be a SIGSEGV pending for
the process. */ return 0xdeadbeef;
}
}
}
#else
/* sys_cacheflush -- flush (part of) the processor cache. */
asmlinkage int
sys_cacheflush (unsignedlong addr, int scope, int cache, unsignedlong len)
{
flush_cache_all(); return 0;
}
/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
D1 (newval). */
asmlinkage int
sys_atomic_cmpxchg_32(unsignedlong newval, int oldval, int d3, int d4, int d5, unsignedlong __user * mem)
{ struct mm_struct *mm = current->mm; unsignedlong mem_value;
mmap_read_lock(mm);
mem_value = *mem; if (mem_value == oldval)
*mem = newval;
mmap_read_unlock(mm); return mem_value;
}
#endif/* CONFIG_MMU */
asmlinkage int sys_getpagesize(void)
{ return PAGE_SIZE;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.