root/arch/m68k/kernel/sys_m68k.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_mmap2
  2. cache_flush_040
  3. cache_flush_060
  4. sys_cacheflush
  5. sys_atomic_cmpxchg_32
  6. sys_cacheflush
  7. sys_atomic_cmpxchg_32
  8. sys_getpagesize
  9. sys_get_thread_area
  10. sys_set_thread_area
  11. sys_atomic_barrier

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

/* [<][>][^][v][top][bottom][index][help] */